@xbongbong/xbbcli 2.0.0 → 2.2.0
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/README.md +101 -2
- package/ai-call-add-task.js +3 -6
- package/ai-word-list.js +3 -6
- package/bin/xbbcli.js +20 -2
- package/buyer-inquiry-detail.js +2 -5
- package/buyer-inquiry-list.js +2 -5
- package/clue-add-couser.js +2 -5
- package/clue-add.js +2 -5
- package/clue-back.js +2 -5
- package/clue-del.js +2 -5
- package/clue-delete-couser.js +2 -5
- package/clue-delete-mainuser.js +2 -5
- package/clue-detail.js +2 -5
- package/clue-distribution.js +2 -5
- package/clue-edit.js +2 -5
- package/clue-handover.js +3 -6
- package/clue-list.js +2 -5
- package/clue-thorough-delete.js +2 -5
- package/communicate-add.js +2 -5
- package/communicate-del.js +2 -5
- package/communicate-detail.js +2 -5
- package/communicate-edit.js +2 -5
- package/communicate-list.js +2 -5
- package/communicate-plan-add.js +2 -5
- package/communicate-plan-cancel.js +2 -5
- package/communicate-plan-del.js +2 -5
- package/communicate-plan-detail.js +2 -5
- package/communicate-plan-list.js +2 -5
- package/communicate-plan-single-operate.js +2 -5
- package/contact-add-couser.js +2 -5
- package/contact-add-mainuser.js +2 -5
- package/contact-add.js +2 -5
- package/contact-del.js +2 -1
- package/contact-delete-couser.js +2 -5
- package/contact-delete-mainuser.js +2 -5
- package/contact-detail.js +2 -1
- package/contact-edit.js +2 -5
- package/contact-handover.js +2 -5
- package/contact-list.js +2 -5
- package/contract-add-couser.js +2 -5
- package/contract-add-mainuser.js +2 -5
- package/contract-add.js +2 -5
- package/contract-del.js +2 -5
- package/contract-delete-couser.js +2 -5
- package/contract-delete-mainuser.js +2 -5
- package/contract-detail.js +2 -5
- package/contract-edit.js +2 -5
- package/contract-handover.js +2 -5
- package/contract-list.js +2 -5
- package/contract-outstock-add.js +2 -5
- package/contract-outstock-del.js +2 -5
- package/contract-outstock-detail.js +2 -5
- package/contract-outstock-edit.js +2 -5
- package/contract-outstock-list.js +2 -5
- package/customer-add-couser.js +2 -5
- package/customer-add.js +2 -5
- package/customer-back.js +2 -5
- package/customer-del.js +2 -5
- package/customer-delete-couser.js +2 -5
- package/customer-delete-mainuser.js +2 -5
- package/customer-detail.js +2 -5
- package/customer-distribution.js +2 -5
- package/customer-edit.js +2 -5
- package/customer-handover.js +2 -5
- package/customer-invoice-address-add.js +2 -5
- package/customer-invoice-address-edit.js +2 -5
- package/customer-invoice-address.js +2 -5
- package/customer-invoice-info-add.js +2 -5
- package/customer-invoice-info-edit.js +2 -5
- package/customer-invoice-info.js +2 -5
- package/customer-list.js +2 -5
- package/department-add.js +2 -5
- package/department-del.js +2 -5
- package/department-edit.js +2 -5
- package/department-list.js +2 -5
- package/form-data-add-couser.js +2 -5
- package/form-data-add-mainuser.js +2 -5
- package/form-data-add.js +2 -5
- package/form-data-del.js +2 -5
- package/form-data-delete-couser.js +2 -5
- package/form-data-delete-mainuser.js +2 -5
- package/form-data-detail.js +2 -5
- package/form-data-edit.js +2 -5
- package/form-data-handover.js +2 -5
- package/form-data-list.js +2 -5
- package/form-get.js +2 -5
- package/form-list.js +2 -5
- package/invoice-add.js +3 -6
- package/invoice-cancel.js +3 -6
- package/invoice-del.js +3 -6
- package/invoice-detail.js +3 -6
- package/invoice-edit.js +3 -6
- package/invoice-get-amount-detail.js +3 -6
- package/invoice-list.js +3 -6
- package/invoice-red.js +3 -6
- package/label-add.js +3 -6
- package/label-all-list.js +3 -6
- package/label-batch-add.js +3 -6
- package/label-batch-remove.js +3 -6
- package/label-del-completely.js +3 -6
- package/label-del.js +3 -6
- package/label-edit.js +3 -6
- package/label-group-add.js +3 -6
- package/label-group-del.js +3 -6
- package/label-group-list.js +3 -6
- package/label-group-update.js +3 -6
- package/label-list.js +3 -6
- package/label-reduction.js +3 -6
- package/label-repeat.js +3 -6
- package/market-activity-add.js +2 -5
- package/market-activity-del.js +2 -5
- package/market-activity-detail.js +2 -5
- package/market-activity-edit.js +2 -5
- package/market-activity-handover.js +2 -5
- package/market-activity-list.js +2 -5
- package/opportunity-add-couser.js +2 -5
- package/opportunity-add-mainuser.js +2 -5
- package/opportunity-add.js +2 -5
- package/opportunity-del.js +2 -5
- package/opportunity-delete-couser.js +2 -5
- package/opportunity-delete-mainuser.js +2 -5
- package/opportunity-detail.js +2 -5
- package/opportunity-edit.js +2 -5
- package/opportunity-handover.js +2 -5
- package/opportunity-list.js +2 -5
- package/package.json +1 -1
- package/pay-plan-add-couser.js +2 -5
- package/pay-plan-add-mainuser.js +2 -5
- package/pay-plan-add.js +2 -5
- package/pay-plan-delete-couser.js +2 -5
- package/pay-plan-delete-mainuser.js +2 -5
- package/pay-plan-handover.js +2 -5
- package/pay-sheet-add-bad.js +2 -5
- package/pay-sheet-add-couser.js +2 -5
- package/pay-sheet-add-mainuser.js +2 -5
- package/pay-sheet-add-red.js +2 -5
- package/pay-sheet-add-write-off.js +2 -5
- package/pay-sheet-del.js +2 -5
- package/pay-sheet-delete-couser.js +2 -5
- package/pay-sheet-delete-mainuser.js +2 -5
- package/pay-sheet-detail.js +2 -5
- package/pay-sheet-edit-bad.js +2 -5
- package/pay-sheet-edit-red.js +2 -5
- package/pay-sheet-edit-write-off.js +2 -5
- package/pay-sheet-get-amount-detail.js +2 -5
- package/pay-sheet-list.js +2 -5
- package/payment-add-couser.js +2 -5
- package/payment-add-mainuser.js +2 -5
- package/payment-add.js +2 -5
- package/payment-del.js +2 -5
- package/payment-delete-couser.js +2 -5
- package/payment-delete-mainuser.js +2 -5
- package/payment-detail.js +2 -5
- package/payment-edit.js +2 -5
- package/payment-handover.js +2 -5
- package/payment-list.js +2 -5
- package/payment-sheet-add-bad-debt.js +2 -5
- package/payment-sheet-add-pre.js +2 -5
- package/payment-sheet-add-red.js +2 -5
- package/payment-sheet-add-write-off.js +2 -5
- package/payment-sheet-del.js +2 -5
- package/payment-sheet-detail.js +2 -5
- package/payment-sheet-edit-bad-debt.js +2 -5
- package/payment-sheet-edit-red.js +2 -5
- package/payment-sheet-edit-write-off.js +2 -5
- package/payment-sheet-get-amount-detail.js +2 -5
- package/payment-sheet-handover.js +2 -5
- package/payment-sheet-list.js +2 -5
- package/product-add.js +2 -5
- package/product-category-add.js +2 -5
- package/product-category-del.js +2 -5
- package/product-category-list.js +2 -5
- package/product-category-update.js +2 -5
- package/product-del.js +2 -5
- package/product-detail.js +2 -5
- package/product-edit.js +2 -5
- package/product-list.js +2 -5
- package/product-online.js +2 -5
- package/quotation-add-couser.js +3 -6
- package/quotation-add-mainuser.js +3 -6
- package/quotation-add.js +3 -6
- package/quotation-del.js +3 -6
- package/quotation-delete-couser.js +3 -6
- package/quotation-delete-mainuser.js +3 -6
- package/quotation-detail.js +3 -6
- package/quotation-edit.js +3 -6
- package/quotation-handover.js +2 -5
- package/quotation-list.js +3 -6
- package/refund-add.js +4 -1
- package/refund-del.js +4 -1
- package/refund-detail.js +4 -1
- package/refund-edit.js +4 -1
- package/refund-list.js +2 -5
- package/role-list.js +2 -5
- package/sign-in-list.js +2 -5
- package/stage-get.js +2 -5
- package/stage-jump.js +2 -5
- package/supplier-add.js +2 -5
- package/token-del.js +106 -0
- package/token-generate.js +2 -5
- package/token-list.js +119 -0
- package/token-set.js +191 -10
- package/token-use.js +102 -0
- package/user-add.js +2 -5
- package/user-del.js +2 -5
- package/user-edit.js +2 -5
- package/user-handover.js +2 -5
- package/user-list.js +5 -8
- package/work-order-add.js +2 -5
- package/work-order-asset-add-couser.js +3 -6
- package/work-order-asset-add-mainuser.js +3 -6
- package/work-order-asset-add.js +3 -6
- package/work-order-asset-del-couser.js +3 -6
- package/work-order-asset-del-mainuser.js +3 -6
- package/work-order-asset-del.js +3 -6
- package/work-order-asset-detail.js +3 -6
- package/work-order-asset-edit.js +3 -6
- package/work-order-asset-handover.js +3 -6
- package/work-order-asset-list.js +3 -6
- package/work-order-del.js +2 -5
- package/work-order-detail.js +2 -5
- package/work-order-dynamic-list.js +2 -5
- package/work-order-edit.js +2 -5
- package/work-order-list.js +2 -5
- package/work-order-operate.js +2 -5
- package/work-order-template-detail.js +2 -5
- package/work-order-template-list.js +2 -5
- package/work-report-daily-add.js +2 -5
- package/work-report-daily-del.js +2 -5
- package/work-report-daily-detail.js +2 -5
- package/work-report-daily-edit.js +2 -5
- package/work-report-daily-get-work-plan.js +2 -5
- package/work-report-daily-list.js +2 -5
- package/work-report-monthly-add.js +2 -5
- package/work-report-monthly-del.js +2 -5
- package/work-report-monthly-detail.js +2 -5
- package/work-report-monthly-edit.js +2 -5
- package/work-report-monthly-list.js +2 -5
- package/work-report-weekly-add.js +2 -5
- package/work-report-weekly-del.js +2 -5
- package/work-report-weekly-detail.js +2 -5
- package/work-report-weekly-edit.js +2 -5
- package/work-report-weekly-list.js +2 -5
- package/work-task-add-couser.js +2 -5
- package/work-task-add.js +2 -5
- package/work-task-delete-couser.js +2 -5
- package/work-task-detail.js +2 -5
- package/work-task-edit.js +2 -5
- package/work-task-handover.js +2 -5
- package/workorder-add-couser.js +2 -5
- package/workorder-delete-couser.js +2 -5
- package/workorder-handover.js +2 -5
- package/workorderlist.js +2 -5
- package/workorderproductlist.js +2 -5
- package/worktimerecorddetail.js +2 -5
- package/worktimerecordlist.js +2 -5
- package/xbb-config.js +113 -0
- package/version.js +0 -18
package/token-generate.js
CHANGED
|
@@ -3,6 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { cli, Strategy } from './xbb-registry.js';
|
|
6
|
+
import { readActiveConfig } from './xbb-config.js';
|
|
6
7
|
|
|
7
8
|
const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
|
|
8
9
|
const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/user/generateToken';
|
|
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
|
|
|
10
11
|
const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
|
|
11
12
|
|
|
12
13
|
function readConfig() {
|
|
13
|
-
|
|
14
|
-
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
15
|
-
} catch {
|
|
16
|
-
return {};
|
|
17
|
-
}
|
|
14
|
+
return readActiveConfig();
|
|
18
15
|
}
|
|
19
16
|
|
|
20
17
|
function resolveBaseUrl(corpid) {
|
package/token-list.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { cli, Strategy } from './xbb-registry.js';
|
|
5
|
+
import { readEnvConfig, hasEnvConfig, isEnvOnly } from './xbb-config.js';
|
|
6
|
+
|
|
7
|
+
const CONFIG_DIR = path.join(os.homedir(), '.xbbcli');
|
|
8
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.env');
|
|
9
|
+
|
|
10
|
+
function readCompanies() {
|
|
11
|
+
try {
|
|
12
|
+
const parsed = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
13
|
+
return normalizeCompanies(parsed);
|
|
14
|
+
} catch {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function normalizeCompanies(parsed) {
|
|
20
|
+
if (Array.isArray(parsed)) {
|
|
21
|
+
return parsed.filter((item) => item && typeof item === 'object');
|
|
22
|
+
}
|
|
23
|
+
if (parsed && Array.isArray(parsed.companies)) {
|
|
24
|
+
return parsed.companies.filter((item) => item && typeof item === 'object');
|
|
25
|
+
}
|
|
26
|
+
if (parsed && parsed.corpid) {
|
|
27
|
+
const { corpid, token, baseurl, userId } = parsed;
|
|
28
|
+
return [{ corpid, token, baseurl, userId, enable: true }];
|
|
29
|
+
}
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function writeCompanies(companies) {
|
|
34
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
35
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(companies, null, 2) + '\n', 'utf8');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function enableOnly(companies, index) {
|
|
39
|
+
return companies.map((item, itemIndex) => ({ ...item, enable: itemIndex === index }));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function enableSingle(companies) {
|
|
43
|
+
const enabledIndex = companies.findIndex((item) => item.enable === true);
|
|
44
|
+
return enableOnly(companies, enabledIndex === -1 ? 0 : enabledIndex);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function maskToken(token) {
|
|
48
|
+
const value = String(token || '').trim();
|
|
49
|
+
if (!value) return '';
|
|
50
|
+
if (value.length <= 12) return `${value.slice(0, 4)}****`;
|
|
51
|
+
return `${value.slice(0, 8)}****${value.slice(-4)}`;
|
|
52
|
+
}
|
|
53
|
+
function makeErrorRow(code, msg) {
|
|
54
|
+
return [{ enable: '', corpid: '', corpName: '', userName: '', userId: '', baseurl: '', token: '', code, msg, source: '' }];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
cli({
|
|
58
|
+
site: 'xbb',
|
|
59
|
+
name: 'token-list',
|
|
60
|
+
description: '列出本地保存的多家公司配置,并标记唯一启用的公司(enable=true)',
|
|
61
|
+
strategy: Strategy.PUBLIC,
|
|
62
|
+
access: 'read',
|
|
63
|
+
browser: false,
|
|
64
|
+
domain: 'proapi.xbongbong.com',
|
|
65
|
+
args: [
|
|
66
|
+
{ name: 'showToken', type: 'bool', default: false, help: '显示完整 token;默认只显示脱敏预览' },
|
|
67
|
+
],
|
|
68
|
+
columns: ['enable', 'corpid', 'userId', 'baseurl', 'token', 'corpName', 'userName', 'code', 'msg', 'source'],
|
|
69
|
+
func: async (kwargs) => {
|
|
70
|
+
const companies = readCompanies();
|
|
71
|
+
const envConfig = readEnvConfig();
|
|
72
|
+
if (isEnvOnly() || (!companies.some((item) => item && item.enable === true) && hasEnvConfig(envConfig))) {
|
|
73
|
+
return [{
|
|
74
|
+
enable: 'true',
|
|
75
|
+
corpid: String(envConfig.corpid || ''),
|
|
76
|
+
userId: String(envConfig.userId || ''),
|
|
77
|
+
baseurl: String(envConfig.baseurl || ''),
|
|
78
|
+
token: Boolean(kwargs.showToken) ? String(envConfig.token || '') : maskToken(envConfig.token),
|
|
79
|
+
corpName: String(envConfig.corpName || ''),
|
|
80
|
+
userName: String(envConfig.userName || ''),
|
|
81
|
+
code: '',
|
|
82
|
+
msg: '来源为环境变量 XBB_*(环境变量模式不支持多公司切换)',
|
|
83
|
+
source: 'env',
|
|
84
|
+
}];
|
|
85
|
+
}
|
|
86
|
+
if (!companies.length) {
|
|
87
|
+
return makeErrorRow('NO_CONFIG', '缺少本地配置;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>');
|
|
88
|
+
}
|
|
89
|
+
const showToken = Boolean(kwargs.showToken);
|
|
90
|
+
const enabledCount = companies.filter((item) => item.enable === true).length;
|
|
91
|
+
const rows = companies.map((item) => ({
|
|
92
|
+
enable: item.enable === true ? 'true' : 'false',
|
|
93
|
+
corpid: String(item.corpid || ''),
|
|
94
|
+
userId: String(item.userId || ''),
|
|
95
|
+
baseurl: String(item.baseurl || ''),
|
|
96
|
+
token: showToken ? String(item.token || '') : maskToken(item.token),
|
|
97
|
+
corpName: String(item.corpName || ''),
|
|
98
|
+
userName: String(item.userName || ''),
|
|
99
|
+
code: '',
|
|
100
|
+
msg: '',
|
|
101
|
+
source: 'config',
|
|
102
|
+
}));
|
|
103
|
+
if (enabledCount !== 1) {
|
|
104
|
+
rows.push({
|
|
105
|
+
enable: '',
|
|
106
|
+
corpid: '',
|
|
107
|
+
userId: '',
|
|
108
|
+
baseurl: '',
|
|
109
|
+
token: '',
|
|
110
|
+
corpName: '',
|
|
111
|
+
userName: '',
|
|
112
|
+
source: 'config',
|
|
113
|
+
code: 'INVALID_ENABLE',
|
|
114
|
+
msg: `配置中启用(enable=true)的公司数量为 ${enabledCount},请用 xbbcli token-use --corpid <CORPID> 修正`,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return rows;
|
|
118
|
+
},
|
|
119
|
+
});
|
package/token-set.js
CHANGED
|
@@ -2,10 +2,15 @@ import fs from 'node:fs';
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { cli, Strategy, getRegistry } from './xbb-registry.js';
|
|
5
|
+
import { persistEnvVars } from './xbb-config.js';
|
|
5
6
|
|
|
6
7
|
const CONFIG_DIR = path.join(os.homedir(), '.xbbcli');
|
|
7
8
|
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.env');
|
|
8
9
|
const FORMLIST_FILE_SUFFIX = '.formlist.json';
|
|
10
|
+
const COMMAND_MAP_FILE_SUFFIX = '.command-map.md';
|
|
11
|
+
const DEPARTMENT_USER_FILE_SUFFIX = '.department-user.json';
|
|
12
|
+
const READ_ALL_PAGE_SIZE = 200;
|
|
13
|
+
const READ_ALL_MAX_PAGES = 1000;
|
|
9
14
|
|
|
10
15
|
function resolveBaseUrl(corpid) {
|
|
11
16
|
if (corpid.startsWith('ding') || corpid.includes('$$ding')) {
|
|
@@ -22,6 +27,10 @@ function getFormlistFile(corpid) {
|
|
|
22
27
|
return path.join(CONFIG_DIR, `${corpid}${FORMLIST_FILE_SUFFIX}`);
|
|
23
28
|
}
|
|
24
29
|
|
|
30
|
+
function getCommandMapFile(corpid) {
|
|
31
|
+
return path.join(CONFIG_DIR, `${corpid}${COMMAND_MAP_FILE_SUFFIX}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
25
34
|
async function runCommandJson(name, kwargs) {
|
|
26
35
|
const command = getRegistry().get(`xbb/${name}`);
|
|
27
36
|
if (!command) throw new Error(`找不到命令:${name}`);
|
|
@@ -45,10 +54,10 @@ async function getFormlistRows(corpid, saasMark) {
|
|
|
45
54
|
return rows;
|
|
46
55
|
}
|
|
47
56
|
|
|
48
|
-
async function
|
|
57
|
+
async function requestPersonalToken(corpid, token, userId, resetToken) {
|
|
49
58
|
const rows = await runCommandJson('token-generate', {
|
|
50
59
|
checkUserId: userId,
|
|
51
|
-
resetToken:
|
|
60
|
+
resetToken: String(resetToken),
|
|
52
61
|
token,
|
|
53
62
|
corpid,
|
|
54
63
|
});
|
|
@@ -62,7 +71,20 @@ async function getPersonalToken(corpid, token, userId) {
|
|
|
62
71
|
throw new Error(`token-generate 获取个人 token 失败:${errorRow.code} ${errorRow.msg || ''}`.trim());
|
|
63
72
|
}
|
|
64
73
|
|
|
65
|
-
|
|
74
|
+
return String(rows[0]?.token || '').trim();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function getPersonalToken(corpid, token, userId) {
|
|
78
|
+
const existingToken = await requestPersonalToken(corpid, token, userId, 0);
|
|
79
|
+
|
|
80
|
+
if (existingToken) {
|
|
81
|
+
if (!existingToken.startsWith('user_')) {
|
|
82
|
+
throw new Error('token-generate 未返回有效的个人 token');
|
|
83
|
+
}
|
|
84
|
+
return existingToken;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const personalToken = await requestPersonalToken(corpid, token, userId, 1);
|
|
66
88
|
if (!personalToken.startsWith('user_')) {
|
|
67
89
|
throw new Error('token-generate 未返回有效的个人 token');
|
|
68
90
|
}
|
|
@@ -80,6 +102,106 @@ async function writeFormlistFile(corpid) {
|
|
|
80
102
|
return formlistFile;
|
|
81
103
|
}
|
|
82
104
|
|
|
105
|
+
function getDepartmentUserFile(corpid) {
|
|
106
|
+
return path.join(CONFIG_DIR, `${corpid}${DEPARTMENT_USER_FILE_SUFFIX}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function fetchAllRows(name, pageSize) {
|
|
110
|
+
const rows = [];
|
|
111
|
+
for (let page = 1; page <= READ_ALL_MAX_PAGES; page += 1) {
|
|
112
|
+
const pageRows = await runCommandJson(name, { page: String(page), pageSize: String(pageSize) });
|
|
113
|
+
const errorRow = pageRows.find((item) => item && String(item.code ?? '') !== '');
|
|
114
|
+
if (errorRow) {
|
|
115
|
+
if (String(errorRow.code) === 'NO_DATA') {
|
|
116
|
+
return rows;
|
|
117
|
+
}
|
|
118
|
+
throw new Error(`${name} 获取失败(page=${page}):${errorRow.code} ${errorRow.msg || ''}`.trim());
|
|
119
|
+
}
|
|
120
|
+
rows.push(...pageRows);
|
|
121
|
+
}
|
|
122
|
+
throw new Error(`${name} 分页超过 ${READ_ALL_MAX_PAGES} 页,未获取到完整数据`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function parseDepartmentListField(value) {
|
|
126
|
+
if (Array.isArray(value)) {
|
|
127
|
+
return value;
|
|
128
|
+
}
|
|
129
|
+
const text = String(value ?? '').trim();
|
|
130
|
+
if (!text) {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
const parsed = JSON.parse(text);
|
|
135
|
+
return Array.isArray(parsed) ? parsed : text;
|
|
136
|
+
} catch {
|
|
137
|
+
return text;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function toDepartmentEntry(row) {
|
|
142
|
+
return {
|
|
143
|
+
id: row.id ?? '',
|
|
144
|
+
name: row.name ?? '',
|
|
145
|
+
parentId: row.parentId ?? '',
|
|
146
|
+
depIdRouter: row.depIdRouter ?? '',
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function toUserEntry(row) {
|
|
151
|
+
return {
|
|
152
|
+
userId: row.userId ?? '',
|
|
153
|
+
name: row.name ?? '',
|
|
154
|
+
position: row.position ?? '',
|
|
155
|
+
jobnumber: row.jobnumber ?? '',
|
|
156
|
+
departmentList: parseDepartmentListField(row.departmentList),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function writeDepartmentUserFile(corpid, userId) {
|
|
161
|
+
const departmentRows = await fetchAllRows('department-list', READ_ALL_PAGE_SIZE);
|
|
162
|
+
const userRows = await fetchAllRows('user-list', READ_ALL_PAGE_SIZE);
|
|
163
|
+
const payload = {
|
|
164
|
+
corpid,
|
|
165
|
+
updatedAt: new Date().toISOString(),
|
|
166
|
+
pageSize: READ_ALL_PAGE_SIZE,
|
|
167
|
+
departmentCount: departmentRows.length,
|
|
168
|
+
userCount: userRows.length,
|
|
169
|
+
departments: departmentRows.map(toDepartmentEntry),
|
|
170
|
+
users: userRows.map(toUserEntry),
|
|
171
|
+
};
|
|
172
|
+
const file = getDepartmentUserFile(corpid);
|
|
173
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
174
|
+
fs.writeFileSync(file, JSON.stringify(payload, null, 2) + '\n', 'utf8');
|
|
175
|
+
return { file, corpName: getCorpName(departmentRows), userName: getUserName(userRows, userId) };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function getCorpName(departmentRows) {
|
|
179
|
+
const root = departmentRows.find((row) => Number(row.id) === 1);
|
|
180
|
+
return root ? String(root.name || '').trim() : '';
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function getUserName(userRows, userId) {
|
|
184
|
+
const target = String(userId || '').trim();
|
|
185
|
+
if (!target) {
|
|
186
|
+
return '';
|
|
187
|
+
}
|
|
188
|
+
const exact = userRows.find((row) => String(row.userId || '').trim() === target);
|
|
189
|
+
const matched = exact || userRows.find((row) => String(row.userId || '').trim().toLowerCase() === target.toLowerCase());
|
|
190
|
+
return matched ? String(matched.name || '').trim() : '';
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function writeCompanyProfile(corpid, profile) {
|
|
194
|
+
const fields = Object.entries(profile).filter(([, value]) => String(value || '').trim() !== '');
|
|
195
|
+
if (!fields.length) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const patch = Object.fromEntries(fields);
|
|
199
|
+
const companies = readCompanies().map((item) => (
|
|
200
|
+
String(item.corpid || '').trim() === corpid ? { ...item, ...patch } : item
|
|
201
|
+
));
|
|
202
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(companies, null, 2) + '\n', 'utf8');
|
|
203
|
+
}
|
|
204
|
+
|
|
83
205
|
function normalizeBusinessType(value) {
|
|
84
206
|
return String(value).trim().replace(/[))\]】,,;;::。!?!?]+$/g, '');
|
|
85
207
|
}
|
|
@@ -137,13 +259,13 @@ function writeCommandMap(corpid) {
|
|
|
137
259
|
);
|
|
138
260
|
}
|
|
139
261
|
|
|
140
|
-
const commandMapFile =
|
|
262
|
+
const commandMapFile = getCommandMapFile(corpid);
|
|
141
263
|
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
142
264
|
fs.writeFileSync(commandMapFile, `${lines.join('\n')}\n`, 'utf8');
|
|
143
265
|
return commandMapFile;
|
|
144
266
|
}
|
|
145
267
|
|
|
146
|
-
function createResult(status, message, corpid, baseurl, userId, formlistFile = '', commandMapFile = '') {
|
|
268
|
+
function createResult(status, message, corpid, baseurl, userId, formlistFile = '', commandMapFile = '', enable = '', companyCount = '', departmentUserFile = '', corpName = '', userName = '', envStored = '', envFile = '') {
|
|
147
269
|
return [{
|
|
148
270
|
status,
|
|
149
271
|
message,
|
|
@@ -151,11 +273,52 @@ function createResult(status, message, corpid, baseurl, userId, formlistFile = '
|
|
|
151
273
|
corpid,
|
|
152
274
|
baseurl,
|
|
153
275
|
userId,
|
|
276
|
+
enable,
|
|
277
|
+
companyCount,
|
|
154
278
|
formlistFile,
|
|
155
279
|
commandMapFile,
|
|
280
|
+
departmentUserFile,
|
|
281
|
+
corpName,
|
|
282
|
+
userName,
|
|
283
|
+
envStored,
|
|
284
|
+
envFile,
|
|
156
285
|
}];
|
|
157
286
|
}
|
|
158
287
|
|
|
288
|
+
function readCompanies() {
|
|
289
|
+
try {
|
|
290
|
+
const parsed = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
291
|
+
return normalizeCompanies(parsed);
|
|
292
|
+
} catch {
|
|
293
|
+
return [];
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function normalizeCompanies(parsed) {
|
|
298
|
+
if (Array.isArray(parsed)) {
|
|
299
|
+
return parsed.filter((item) => item && typeof item === 'object');
|
|
300
|
+
}
|
|
301
|
+
if (parsed && Array.isArray(parsed.companies)) {
|
|
302
|
+
return parsed.companies.filter((item) => item && typeof item === 'object');
|
|
303
|
+
}
|
|
304
|
+
if (parsed && parsed.corpid) {
|
|
305
|
+
const { corpid, token, baseurl, userId } = parsed;
|
|
306
|
+
return [{ corpid, token, baseurl, userId, enable: true }];
|
|
307
|
+
}
|
|
308
|
+
return [];
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function upsertCompany(companies, entry) {
|
|
312
|
+
const index = companies.findIndex((item) => String(item.corpid || '').trim() === entry.corpid);
|
|
313
|
+
const next = companies.map((item) => ({ ...item, enable: false }));
|
|
314
|
+
if (index === -1) {
|
|
315
|
+
next.push({ ...entry, enable: true });
|
|
316
|
+
} else {
|
|
317
|
+
next[index] = { ...next[index], ...entry, enable: true };
|
|
318
|
+
}
|
|
319
|
+
return next;
|
|
320
|
+
}
|
|
321
|
+
|
|
159
322
|
async function setToken(kwargs) {
|
|
160
323
|
const corpid = normalizeArg(kwargs.corpid);
|
|
161
324
|
const token = normalizeArg(kwargs.token);
|
|
@@ -183,15 +346,29 @@ async function setToken(kwargs) {
|
|
|
183
346
|
}
|
|
184
347
|
|
|
185
348
|
const baseurl = resolveBaseUrl(corpid);
|
|
186
|
-
const
|
|
349
|
+
const companies = upsertCompany(readCompanies(), { corpid, token: personalToken, baseurl, userId });
|
|
187
350
|
|
|
188
351
|
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
189
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify(
|
|
352
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(companies, null, 2) + '\n', 'utf8');
|
|
190
353
|
|
|
191
354
|
try {
|
|
192
355
|
const formlistFile = await writeFormlistFile(corpid);
|
|
193
356
|
const commandMapFile = writeCommandMap(corpid);
|
|
194
|
-
|
|
357
|
+
const { file: departmentUserFile, corpName, userName } = await writeDepartmentUserFile(corpid, userId);
|
|
358
|
+
writeCompanyProfile(corpid, { corpName, userName });
|
|
359
|
+
let envStored = 'skipped';
|
|
360
|
+
let envFile = '';
|
|
361
|
+
if (!kwargs.noEnv) {
|
|
362
|
+
try {
|
|
363
|
+
const envResult = persistEnvVars({ corpid, token: personalToken, baseurl, userId, corpName, userName });
|
|
364
|
+
envStored = envResult.stored;
|
|
365
|
+
envFile = envResult.file;
|
|
366
|
+
} catch (error) {
|
|
367
|
+
envStored = 'failed';
|
|
368
|
+
envFile = String(error.message || error);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return createResult('ok', '已保存 corpid、token、baseurl、userId,并同步表单模板缓存、命令映射文件与部门/员工缓存', corpid, baseurl, userId, formlistFile, commandMapFile, true, companies.length, departmentUserFile, corpName, userName, envStored, envFile);
|
|
195
372
|
} catch (error) {
|
|
196
373
|
return createResult(
|
|
197
374
|
'partial',
|
|
@@ -201,6 +378,9 @@ async function setToken(kwargs) {
|
|
|
201
378
|
userId,
|
|
202
379
|
getFormlistFile(corpid),
|
|
203
380
|
'',
|
|
381
|
+
true,
|
|
382
|
+
companies.length,
|
|
383
|
+
'',
|
|
204
384
|
);
|
|
205
385
|
}
|
|
206
386
|
}
|
|
@@ -208,7 +388,7 @@ async function setToken(kwargs) {
|
|
|
208
388
|
cli({
|
|
209
389
|
site: 'xbb',
|
|
210
390
|
name: 'token-set',
|
|
211
|
-
description: '保存 xbb API token,corpid,formId清单
|
|
391
|
+
description: '保存 xbb API token,corpid,formId清单 到本地配置文件,并缓存部门与员工清单(<corpid>.department-user.json);其他命令需要意图识别或找formId时,优先查命令映射文件(<corpid>.command-map.md)',
|
|
212
392
|
strategy: Strategy.PUBLIC,
|
|
213
393
|
access: 'write',
|
|
214
394
|
browser: false,
|
|
@@ -216,7 +396,8 @@ cli({
|
|
|
216
396
|
{ name: 'corpid', type: 'str', help: '公司id(必填)' },
|
|
217
397
|
{ name: 'token', type: 'str', help: '要保存的 API token' },
|
|
218
398
|
{ name: 'userId', type: 'str', help: '操作人id(必填)' },
|
|
399
|
+
{ name: 'noEnv', type: 'bool', default: false, help: '不写入环境变量,仅保存到 config.env' },
|
|
219
400
|
],
|
|
220
|
-
columns: ['status', 'message', 'configFile', 'corpid', 'baseurl', 'userId', 'formlistFile', 'commandMapFile'],
|
|
401
|
+
columns: ['status', 'message', 'configFile', 'corpid', 'baseurl', 'userId', 'enable', 'companyCount', 'formlistFile', 'commandMapFile', 'departmentUserFile', 'corpName', 'userName', 'envStored', 'envFile'],
|
|
221
402
|
func: setToken,
|
|
222
403
|
});
|
package/token-use.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { cli, Strategy } from './xbb-registry.js';
|
|
5
|
+
import { isEnvActive, isEnvOnly, getEnvVarNames } from './xbb-config.js';
|
|
6
|
+
|
|
7
|
+
const CONFIG_DIR = path.join(os.homedir(), '.xbbcli');
|
|
8
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.env');
|
|
9
|
+
|
|
10
|
+
function readCompanies() {
|
|
11
|
+
try {
|
|
12
|
+
const parsed = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
13
|
+
return normalizeCompanies(parsed);
|
|
14
|
+
} catch {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function normalizeCompanies(parsed) {
|
|
20
|
+
if (Array.isArray(parsed)) {
|
|
21
|
+
return parsed.filter((item) => item && typeof item === 'object');
|
|
22
|
+
}
|
|
23
|
+
if (parsed && Array.isArray(parsed.companies)) {
|
|
24
|
+
return parsed.companies.filter((item) => item && typeof item === 'object');
|
|
25
|
+
}
|
|
26
|
+
if (parsed && parsed.corpid) {
|
|
27
|
+
const { corpid, token, baseurl, userId } = parsed;
|
|
28
|
+
return [{ corpid, token, baseurl, userId, enable: true }];
|
|
29
|
+
}
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function writeCompanies(companies) {
|
|
34
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
35
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(companies, null, 2) + '\n', 'utf8');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function enableOnly(companies, index) {
|
|
39
|
+
return companies.map((item, itemIndex) => ({ ...item, enable: itemIndex === index }));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function enableSingle(companies) {
|
|
43
|
+
const enabledIndex = companies.findIndex((item) => item.enable === true);
|
|
44
|
+
return enableOnly(companies, enabledIndex === -1 ? 0 : enabledIndex);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function maskToken(token) {
|
|
48
|
+
const value = String(token || '').trim();
|
|
49
|
+
if (!value) return '';
|
|
50
|
+
if (value.length <= 12) return `${value.slice(0, 4)}****`;
|
|
51
|
+
return `${value.slice(0, 8)}****${value.slice(-4)}`;
|
|
52
|
+
}
|
|
53
|
+
function createResult(status, message, corpid, enable, companyCount) {
|
|
54
|
+
return [{
|
|
55
|
+
status,
|
|
56
|
+
message,
|
|
57
|
+
configFile: CONFIG_FILE,
|
|
58
|
+
corpid,
|
|
59
|
+
enable,
|
|
60
|
+
companyCount,
|
|
61
|
+
}];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function useCompany(kwargs) {
|
|
65
|
+
const corpid = String(kwargs.corpid || '').trim();
|
|
66
|
+
if (!corpid) {
|
|
67
|
+
return createResult('error', '缺少 --corpid', '', '', '');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (isEnvOnly() || isEnvActive()) {
|
|
71
|
+
return createResult('error', `当前为环境变量模式(${getEnvVarNames().join(', ')}),不支持切换公司;如需多公司请改用 config.env`, corpid, '', '');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const companies = readCompanies();
|
|
75
|
+
if (!companies.length) {
|
|
76
|
+
return createResult('error', '缺少本地配置;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>', corpid, '', 0);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const index = companies.findIndex((item) => String(item.corpid || '').trim() === corpid);
|
|
80
|
+
if (index === -1) {
|
|
81
|
+
return createResult('error', `未找到 corpid=${corpid} 的本地配置`, corpid, '', companies.length);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const next = enableOnly(companies, index);
|
|
85
|
+
writeCompanies(next);
|
|
86
|
+
return createResult('ok', `已启用 corpid=${corpid},其余公司已标记为 enable=false`, corpid, 'true', next.length);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
cli({
|
|
90
|
+
site: 'xbb',
|
|
91
|
+
name: 'token-use',
|
|
92
|
+
description: '切换当前启用的公司(enable),保证仅且只有一个公司被启用',
|
|
93
|
+
strategy: Strategy.PUBLIC,
|
|
94
|
+
access: 'write',
|
|
95
|
+
browser: false,
|
|
96
|
+
domain: 'proapi.xbongbong.com',
|
|
97
|
+
args: [
|
|
98
|
+
{ name: 'corpid', type: 'str', help: '要启用的公司 id,必须是已保存的 corpid(必填)' },
|
|
99
|
+
],
|
|
100
|
+
columns: ['status', 'message', 'configFile', 'corpid', 'enable', 'companyCount'],
|
|
101
|
+
func: useCompany,
|
|
102
|
+
});
|
package/user-add.js
CHANGED
|
@@ -3,6 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { cli, Strategy } from './xbb-registry.js';
|
|
6
|
+
import { readActiveConfig } from './xbb-config.js';
|
|
6
7
|
|
|
7
8
|
const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
|
|
8
9
|
const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/user/add';
|
|
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
|
|
|
10
11
|
const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
|
|
11
12
|
|
|
12
13
|
function readConfig() {
|
|
13
|
-
|
|
14
|
-
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
15
|
-
} catch {
|
|
16
|
-
return {};
|
|
17
|
-
}
|
|
14
|
+
return readActiveConfig();
|
|
18
15
|
}
|
|
19
16
|
|
|
20
17
|
function getRuntimeConfig() {
|
package/user-del.js
CHANGED
|
@@ -3,6 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { cli, Strategy } from './xbb-registry.js';
|
|
6
|
+
import { readActiveConfig } from './xbb-config.js';
|
|
6
7
|
|
|
7
8
|
const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
|
|
8
9
|
const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/user/del';
|
|
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
|
|
|
10
11
|
const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
|
|
11
12
|
|
|
12
13
|
function readConfig() {
|
|
13
|
-
|
|
14
|
-
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
15
|
-
} catch {
|
|
16
|
-
return {};
|
|
17
|
-
}
|
|
14
|
+
return readActiveConfig();
|
|
18
15
|
}
|
|
19
16
|
|
|
20
17
|
function getRuntimeConfig() {
|
package/user-edit.js
CHANGED
|
@@ -3,6 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { cli, Strategy } from './xbb-registry.js';
|
|
6
|
+
import { readActiveConfig } from './xbb-config.js';
|
|
6
7
|
|
|
7
8
|
const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
|
|
8
9
|
const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/user/edit';
|
|
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
|
|
|
10
11
|
const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
|
|
11
12
|
|
|
12
13
|
function readConfig() {
|
|
13
|
-
|
|
14
|
-
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
15
|
-
} catch {
|
|
16
|
-
return {};
|
|
17
|
-
}
|
|
14
|
+
return readActiveConfig();
|
|
18
15
|
}
|
|
19
16
|
|
|
20
17
|
function getRuntimeConfig() {
|
package/user-handover.js
CHANGED
|
@@ -3,6 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { cli, Strategy } from './xbb-registry.js';
|
|
6
|
+
import { readActiveConfig } from './xbb-config.js';
|
|
6
7
|
|
|
7
8
|
const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
|
|
8
9
|
const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/user/handover';
|
|
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
|
|
|
10
11
|
const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
|
|
11
12
|
|
|
12
13
|
function readConfig() {
|
|
13
|
-
|
|
14
|
-
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
15
|
-
} catch {
|
|
16
|
-
return {};
|
|
17
|
-
}
|
|
14
|
+
return readActiveConfig();
|
|
18
15
|
}
|
|
19
16
|
|
|
20
17
|
function getRuntimeConfig() {
|
package/user-list.js
CHANGED
|
@@ -3,6 +3,7 @@ import os from 'node:os';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import crypto from 'node:crypto';
|
|
5
5
|
import { cli, Strategy } from './xbb-registry.js';
|
|
6
|
+
import { readActiveConfig } from './xbb-config.js';
|
|
6
7
|
|
|
7
8
|
const CONFIG_DIR = path.join(os.homedir(), '.xbbcli');
|
|
8
9
|
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.env');
|
|
@@ -11,11 +12,7 @@ const USER_LIST_API_PATH = '/pro/v2/api/user/list';
|
|
|
11
12
|
let lastPagination = null;
|
|
12
13
|
|
|
13
14
|
function readConfig() {
|
|
14
|
-
|
|
15
|
-
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
16
|
-
} catch {
|
|
17
|
-
return {};
|
|
18
|
-
}
|
|
15
|
+
return readActiveConfig();
|
|
19
16
|
}
|
|
20
17
|
|
|
21
18
|
function getRuntimeConfig() {
|
|
@@ -53,7 +50,7 @@ function makeErrorRow(code, msg) {
|
|
|
53
50
|
name: '',
|
|
54
51
|
position: '',
|
|
55
52
|
jobnumber: '',
|
|
56
|
-
|
|
53
|
+
departmentList: '',
|
|
57
54
|
code,
|
|
58
55
|
msg,
|
|
59
56
|
}];
|
|
@@ -78,7 +75,7 @@ cli({
|
|
|
78
75
|
{ name: 'debug', type: 'bool', default: false, help: '输出请求体和返回体调试信息' },
|
|
79
76
|
{ name: 'raw', type: 'bool', default: false, help: '输出接口返回的原文' },
|
|
80
77
|
],
|
|
81
|
-
columns: ['rank', 'userId', 'name', 'position', 'jobnumber', '
|
|
78
|
+
columns: ['rank', 'userId', 'name', 'position', 'jobnumber', 'departmentList', 'code', 'msg'],
|
|
82
79
|
footerExtra: () => (lastPagination ? `totalCount ${lastPagination.totalCount} / totalPage ${lastPagination.totalPage}` : undefined),
|
|
83
80
|
func: async (kwargs) => {
|
|
84
81
|
const debug = Boolean(kwargs.debug);
|
|
@@ -139,7 +136,7 @@ cli({
|
|
|
139
136
|
name: item.name || '',
|
|
140
137
|
position: item.position || '',
|
|
141
138
|
jobnumber: item.jobnumber || '',
|
|
142
|
-
|
|
139
|
+
departmentList: Array.isArray(item.departmentList) ? JSON.stringify(item.departmentList) : (item.departmentList || ''),
|
|
143
140
|
code: '',
|
|
144
141
|
msg: '',
|
|
145
142
|
}));
|