@xbongbong/xbbcli 2.4.5 → 2.4.6

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 (258) hide show
  1. package/README.md +15 -4
  2. package/business-info-detail.js +126 -0
  3. package/business-info-search.js +95 -0
  4. package/buyer-inquiry-detail.js +16 -47
  5. package/buyer-inquiry-list.js +18 -56
  6. package/clue-add-couser.js +14 -39
  7. package/clue-add.js +15 -41
  8. package/clue-back.js +14 -39
  9. package/clue-del.js +14 -39
  10. package/clue-delete-couser.js +14 -39
  11. package/clue-delete-mainuser.js +14 -39
  12. package/clue-detail.js +15 -40
  13. package/clue-distribution.js +14 -43
  14. package/clue-edit.js +15 -41
  15. package/clue-handover.js +15 -45
  16. package/clue-list.js +18 -61
  17. package/clue-thorough-delete.js +14 -39
  18. package/communicate-add.js +15 -56
  19. package/communicate-del.js +17 -59
  20. package/communicate-detail.js +15 -56
  21. package/communicate-edit.js +15 -56
  22. package/communicate-list.js +17 -62
  23. package/communicate-plan-add.js +16 -42
  24. package/communicate-plan-cancel.js +14 -40
  25. package/communicate-plan-del.js +14 -40
  26. package/communicate-plan-detail.js +15 -41
  27. package/communicate-plan-list.js +18 -46
  28. package/communicate-plan-single-operate.js +14 -39
  29. package/contact-add-couser.js +14 -39
  30. package/contact-add-mainuser.js +14 -39
  31. package/contact-add.js +15 -51
  32. package/contact-del.js +15 -38
  33. package/contact-delete-couser.js +14 -39
  34. package/contact-delete-mainuser.js +14 -39
  35. package/contact-detail.js +15 -38
  36. package/contact-edit.js +14 -47
  37. package/contact-handover.js +14 -39
  38. package/contact-list.js +37 -61
  39. package/contract-add-couser.js +16 -58
  40. package/contract-add-mainuser.js +16 -58
  41. package/contract-add.js +15 -57
  42. package/contract-del.js +17 -58
  43. package/contract-delete-couser.js +16 -57
  44. package/contract-delete-mainuser.js +16 -58
  45. package/contract-detail.js +15 -57
  46. package/contract-edit.js +15 -57
  47. package/contract-handover.js +15 -56
  48. package/contract-list.js +18 -61
  49. package/contract-outstock-add.js +15 -46
  50. package/contract-outstock-del.js +15 -41
  51. package/contract-outstock-detail.js +15 -41
  52. package/contract-outstock-edit.js +15 -46
  53. package/contract-outstock-list.js +18 -46
  54. package/customer-add-couser.js +13 -54
  55. package/customer-add.js +15 -58
  56. package/customer-back.js +15 -57
  57. package/customer-del.js +17 -58
  58. package/customer-delete-couser.js +16 -57
  59. package/customer-delete-mainuser.js +16 -58
  60. package/customer-detail.js +13 -54
  61. package/customer-distribution.js +15 -57
  62. package/customer-edit.js +13 -53
  63. package/customer-handover.js +15 -56
  64. package/customer-invoice-address-add.js +15 -41
  65. package/customer-invoice-address-edit.js +15 -40
  66. package/customer-invoice-address.js +17 -42
  67. package/customer-invoice-info-add.js +15 -41
  68. package/customer-invoice-info-edit.js +15 -40
  69. package/customer-invoice-info.js +17 -42
  70. package/customer-list.js +18 -61
  71. package/department-add.js +14 -39
  72. package/department-del.js +14 -40
  73. package/department-edit.js +14 -39
  74. package/department-list.js +17 -59
  75. package/form-data-add-couser.js +14 -39
  76. package/form-data-add-mainuser.js +14 -39
  77. package/form-data-add.js +13 -54
  78. package/form-data-del.js +13 -53
  79. package/form-data-delete-couser.js +14 -40
  80. package/form-data-delete-mainuser.js +14 -39
  81. package/form-data-detail.js +13 -54
  82. package/form-data-edit.js +13 -54
  83. package/form-data-handover.js +14 -39
  84. package/form-data-list.js +37 -63
  85. package/form-get.js +13 -53
  86. package/form-list.js +19 -66
  87. package/hkh-call-add-task.js +14 -44
  88. package/hkh-word-list.js +16 -44
  89. package/invoice-add.js +15 -45
  90. package/invoice-cancel.js +14 -44
  91. package/invoice-del.js +15 -45
  92. package/invoice-detail.js +15 -45
  93. package/invoice-edit.js +15 -45
  94. package/invoice-get-amount-detail.js +14 -44
  95. package/invoice-list.js +18 -50
  96. package/invoice-red.js +15 -45
  97. package/label-add.js +14 -44
  98. package/label-all-list.js +16 -44
  99. package/label-batch-add.js +14 -44
  100. package/label-batch-remove.js +14 -44
  101. package/label-del-completely.js +14 -44
  102. package/label-del.js +15 -45
  103. package/label-edit.js +14 -44
  104. package/label-group-add.js +15 -45
  105. package/label-group-del.js +15 -45
  106. package/label-group-list.js +16 -44
  107. package/label-group-update.js +15 -45
  108. package/label-list.js +16 -44
  109. package/label-reduction.js +15 -45
  110. package/label-repeat.js +15 -45
  111. package/market-activity-add.js +14 -49
  112. package/market-activity-del.js +15 -46
  113. package/market-activity-detail.js +15 -45
  114. package/market-activity-edit.js +15 -46
  115. package/market-activity-handover.js +14 -40
  116. package/market-activity-list.js +18 -46
  117. package/opportunity-add-couser.js +16 -58
  118. package/opportunity-add-mainuser.js +16 -58
  119. package/opportunity-add.js +15 -56
  120. package/opportunity-del.js +17 -59
  121. package/opportunity-delete-couser.js +16 -58
  122. package/opportunity-delete-mainuser.js +16 -57
  123. package/opportunity-detail.js +15 -58
  124. package/opportunity-edit.js +15 -56
  125. package/opportunity-handover.js +15 -57
  126. package/opportunity-list.js +40 -65
  127. package/orginal-text-list.js +16 -61
  128. package/package.json +8 -1
  129. package/pay-plan-add-couser.js +14 -41
  130. package/pay-plan-add-mainuser.js +14 -41
  131. package/pay-plan-add.js +15 -46
  132. package/pay-plan-delete-couser.js +14 -40
  133. package/pay-plan-delete-mainuser.js +14 -40
  134. package/pay-plan-handover.js +14 -40
  135. package/pay-sheet-add-bad.js +15 -46
  136. package/pay-sheet-add-couser.js +14 -40
  137. package/pay-sheet-add-mainuser.js +14 -41
  138. package/pay-sheet-add-red.js +15 -46
  139. package/pay-sheet-add-write-off.js +15 -46
  140. package/pay-sheet-del.js +14 -48
  141. package/pay-sheet-delete-couser.js +14 -40
  142. package/pay-sheet-delete-mainuser.js +14 -41
  143. package/pay-sheet-detail.js +15 -46
  144. package/pay-sheet-edit-bad.js +14 -49
  145. package/pay-sheet-edit-red.js +14 -49
  146. package/pay-sheet-edit-write-off.js +15 -46
  147. package/pay-sheet-get-amount-detail.js +14 -44
  148. package/pay-sheet-list.js +18 -46
  149. package/payment-add-couser.js +16 -58
  150. package/payment-add-mainuser.js +16 -58
  151. package/payment-add.js +15 -56
  152. package/payment-del.js +17 -58
  153. package/payment-delete-couser.js +16 -57
  154. package/payment-delete-mainuser.js +16 -57
  155. package/payment-detail.js +15 -56
  156. package/payment-edit.js +15 -56
  157. package/payment-handover.js +15 -57
  158. package/payment-list.js +37 -61
  159. package/payment-sheet-add-bad-debt.js +15 -57
  160. package/payment-sheet-add-pre.js +15 -46
  161. package/payment-sheet-add-red.js +15 -57
  162. package/payment-sheet-add-write-off.js +15 -52
  163. package/payment-sheet-del.js +17 -53
  164. package/payment-sheet-detail.js +15 -52
  165. package/payment-sheet-edit-bad-debt.js +15 -51
  166. package/payment-sheet-edit-red.js +15 -56
  167. package/payment-sheet-edit-write-off.js +15 -56
  168. package/payment-sheet-get-amount-detail.js +14 -45
  169. package/payment-sheet-handover.js +14 -40
  170. package/payment-sheet-list.js +37 -60
  171. package/product-add.js +15 -51
  172. package/product-category-add.js +13 -48
  173. package/product-category-del.js +13 -53
  174. package/product-category-list.js +17 -60
  175. package/product-category-update.js +13 -54
  176. package/product-del.js +17 -53
  177. package/product-detail.js +13 -54
  178. package/product-edit.js +15 -51
  179. package/product-list.js +37 -63
  180. package/product-online.js +14 -44
  181. package/quotation-add-couser.js +15 -45
  182. package/quotation-add-mainuser.js +15 -45
  183. package/quotation-add.js +15 -45
  184. package/quotation-del.js +15 -45
  185. package/quotation-delete-couser.js +15 -45
  186. package/quotation-delete-mainuser.js +15 -45
  187. package/quotation-detail.js +15 -45
  188. package/quotation-edit.js +15 -45
  189. package/quotation-handover.js +14 -39
  190. package/quotation-list.js +18 -50
  191. package/refund-add.js +15 -39
  192. package/refund-del.js +15 -38
  193. package/refund-detail.js +15 -39
  194. package/refund-edit.js +15 -39
  195. package/refund-list.js +37 -61
  196. package/role-list.js +18 -46
  197. package/sign-in-list.js +21 -49
  198. package/stage-get.js +16 -42
  199. package/stage-jump.js +15 -49
  200. package/supplier-add.js +15 -57
  201. package/token-del.js +1 -1
  202. package/token-list.js +20 -1
  203. package/token-set.js +1 -1
  204. package/token-use.js +2 -35
  205. package/user-add.js +14 -39
  206. package/user-del.js +14 -40
  207. package/user-edit.js +14 -40
  208. package/user-handover.js +14 -40
  209. package/user-list.js +16 -62
  210. package/work-order-add.js +13 -54
  211. package/work-order-asset-add-couser.js +15 -45
  212. package/work-order-asset-add-mainuser.js +15 -45
  213. package/work-order-asset-add.js +15 -45
  214. package/work-order-asset-del-couser.js +15 -45
  215. package/work-order-asset-del-mainuser.js +15 -45
  216. package/work-order-asset-del.js +15 -45
  217. package/work-order-asset-detail.js +15 -45
  218. package/work-order-asset-edit.js +15 -45
  219. package/work-order-asset-handover.js +15 -45
  220. package/work-order-asset-list.js +18 -50
  221. package/work-order-del.js +13 -54
  222. package/work-order-detail.js +13 -53
  223. package/work-order-dynamic-list.js +18 -56
  224. package/work-order-edit.js +13 -54
  225. package/work-order-list.js +17 -59
  226. package/work-order-operate.js +13 -54
  227. package/work-order-template-detail.js +13 -54
  228. package/work-order-template-list.js +17 -60
  229. package/work-report-daily-add.js +14 -39
  230. package/work-report-daily-del.js +14 -39
  231. package/work-report-daily-detail.js +15 -40
  232. package/work-report-daily-edit.js +17 -52
  233. package/work-report-daily-get-work-plan.js +14 -40
  234. package/work-report-daily-list.js +18 -45
  235. package/work-report-monthly-add.js +14 -40
  236. package/work-report-monthly-del.js +14 -43
  237. package/work-report-monthly-detail.js +15 -40
  238. package/work-report-monthly-edit.js +15 -40
  239. package/work-report-monthly-list.js +18 -45
  240. package/work-report-weekly-add.js +14 -40
  241. package/work-report-weekly-del.js +14 -40
  242. package/work-report-weekly-detail.js +15 -41
  243. package/work-report-weekly-edit.js +15 -41
  244. package/work-report-weekly-list.js +18 -45
  245. package/work-task-add-couser.js +14 -43
  246. package/work-task-add.js +15 -41
  247. package/work-task-delete-couser.js +14 -40
  248. package/work-task-detail.js +15 -40
  249. package/work-task-edit.js +14 -39
  250. package/work-task-handover.js +14 -40
  251. package/workorder-add-couser.js +16 -57
  252. package/workorder-delete-couser.js +16 -58
  253. package/workorder-handover.js +17 -58
  254. package/workorderlist.js +38 -60
  255. package/workorderproductlist.js +18 -59
  256. package/worktimerecorddetail.js +13 -54
  257. package/worktimerecordlist.js +18 -59
  258. package/xbb-http.js +71 -0
@@ -1,34 +1,9 @@
1
- import crypto from 'node:crypto';
2
- import fs from 'node:fs';
3
- import os from 'node:os';
4
- import path from 'node:path';
5
1
  import { cli, Strategy } from './xbb-registry.js';
6
- import { readActiveConfig } from './xbb-config.js';
2
+ import { getRuntimeConfig, requestGateway } from './xbb-http.js';
7
3
 
8
- const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
9
- const WORK_TIME_RECORD_DETAIL_API_URL = 'https://proapi.xbongbong.com/pro/v2/api/workTimeRecord/detail';
10
- const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
4
+ const WORK_TIME_RECORD_DETAIL_API_PATH = '/pro/v2/api/workTimeRecord/detail';
11
5
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
12
6
 
13
- function readConfig() {
14
- return readActiveConfig();
15
- }
16
-
17
- function getRuntimeConfig() {
18
- const config = readConfig();
19
- return {
20
- corpid: String(config.corpid || '').trim(),
21
- token: String(config.token || '').trim(),
22
- baseUrl: String(config.baseurl || DEFAULT_BASE_URL).trim(),
23
- userId: String(config.userId || '').trim(),
24
- };
25
- }
26
-
27
- function buildApiUrl(baseUrl, apiUrl) {
28
- const apiPath = new URL(apiUrl).pathname;
29
- return `${baseUrl.replace(/\/+$/, '')}${apiPath}`;
30
- }
31
-
32
7
  function buildPayload(kwargs, corpid) {
33
8
  const payload = {
34
9
  dataId: Number(kwargs.dataId || 0),
@@ -114,41 +89,25 @@ cli({
114
89
  const debug = Boolean(kwargs.debug);
115
90
  const { corpid, token, baseUrl, userId } = getRuntimeConfig();
116
91
  const payload = buildPayload(kwargs, corpid);
117
- const requestBody = JSON.stringify(payload);
118
92
 
119
93
  const validationError = getValidationError(payload, token);
120
94
  if (validationError) {
121
95
  return makeErrorRow(validationError.code, validationError.msg);
122
96
  }
123
97
 
124
- const sign = crypto.createHash('sha256').update(requestBody + token).digest('hex');
125
- const apiUrl = buildApiUrl(baseUrl, WORK_TIME_RECORD_DETAIL_API_URL);
126
- const headers = Object.assign({
127
- 'Content-Type': 'application/json;charset=UTF-8',
128
- sign,
129
- }, userId ? { userId } : {});
130
- if (debug) {
131
- process.stderr.write(`[debug] URL: ${apiUrl}\n[debug] Headers: ${JSON.stringify(headers)}\n[debug] RequestBody: ${requestBody}\n`);
132
- }
133
- const resp = await fetch(apiUrl, {
134
- method: 'POST',
135
- headers,
136
- body: requestBody,
98
+ const gateway = await requestGateway({
99
+ baseUrl,
100
+ apiPath: WORK_TIME_RECORD_DETAIL_API_PATH,
101
+ payload,
102
+ token,
103
+ userId,
104
+ debug,
137
105
  });
138
-
139
- if (!resp.ok) {
140
- const responseText = await resp.text();
141
- if (debug) process.stderr.write(`[debug] ResponseBody: ${responseText}\n`);
142
- return makeErrorRow(resp.status, `HTTP ${resp.status} ${resp.statusText}`);
143
- }
144
-
145
- const data = await resp.json();
146
- const responseBody = JSON.stringify(data);
147
- if (debug) process.stderr.write(`[debug] ResponseBody: ${responseBody}\n`);
148
- if (data.code !== 1) {
149
- return makeErrorRow(data.code ?? '', data.msg ?? '未知错误');
106
+ if (!gateway.ok) return makeErrorRow(gateway.code, gateway.msg);
107
+ if (gateway.data.code !== 1) {
108
+ return makeErrorRow(gateway.data.code ?? '', gateway.data.msg ?? '未知错误');
150
109
  }
151
110
 
152
- return makeSuccessRow(data);
111
+ return makeSuccessRow(gateway.data);
153
112
  },
154
113
  });
@@ -1,34 +1,9 @@
1
- import crypto from 'node:crypto';
2
- import fs from 'node:fs';
3
- import os from 'node:os';
4
- import path from 'node:path';
5
1
  import { cli, Strategy } from './xbb-registry.js';
6
- import { readActiveConfig } from './xbb-config.js';
2
+ import { getRuntimeConfig, requestGateway, createPagination } from './xbb-http.js';
7
3
 
8
- const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
9
- const WORK_TIME_RECORD_LIST_API_URL = 'https://proapi.xbongbong.com/pro/v2/api/workTimeRecord/list';
10
- const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
4
+ const WORK_TIME_RECORD_LIST_API_PATH = '/pro/v2/api/workTimeRecord/list';
11
5
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
12
- let lastPagination = null;
13
-
14
- function readConfig() {
15
- return readActiveConfig();
16
- }
17
-
18
- function getRuntimeConfig() {
19
- const config = readConfig();
20
- return {
21
- corpid: String(config.corpid || '').trim(),
22
- token: String(config.token || '').trim(),
23
- baseUrl: String(config.baseurl || DEFAULT_BASE_URL).trim(),
24
- userId: String(config.userId || '').trim(),
25
- };
26
- }
27
-
28
- function buildApiUrl(baseUrl, apiUrl) {
29
- const apiPath = new URL(apiUrl).pathname;
30
- return `${baseUrl.replace(/\/+$/, '')}${apiPath}`;
31
- }
6
+ const pagination = createPagination();
32
7
 
33
8
  function buildConditions(kwargs) {
34
9
  const conditions = kwargs.conditions;
@@ -135,9 +110,10 @@ cli({
135
110
  { name: 'page', type: 'int', default: 1, help: '页码' },
136
111
  { name: 'pageSize', type: 'int', default: 20, help: '每页数量(最大100)' },
137
112
  { name: 'debug', type: 'bool', default: false, help: '输出请求体和返回体调试信息' },
113
+ { name: 'raw', type: 'bool', default: false, help: '输出接口返回的原文' },
138
114
  ],
139
115
  columns: ['rank', 'dataId', 'formId', 'serialNo', 'creatorId', 'ownerId', 'coUserId', 'addTime', 'updateTime', 'data', 'code', 'msg'],
140
- footerExtra: () => (lastPagination ? `totalCount ${lastPagination.totalCount} / totalPage ${lastPagination.totalPage}` : undefined),
116
+ footerExtra: pagination.footerExtra,
141
117
  func: async function (kwargs) {
142
118
  const debug = Boolean(kwargs.debug);
143
119
  const { corpid, token, baseUrl, userId } = getRuntimeConfig();
@@ -148,45 +124,28 @@ cli({
148
124
  return makeErrorRow('INVALID_CONDITIONS', 'conditions 不是合法 JSON');
149
125
  }
150
126
 
151
- const requestBody = JSON.stringify(payload);
152
127
 
153
128
  const validationError = getValidationError(payload, token);
154
129
  if (validationError) {
155
130
  return makeErrorRow(validationError.code, validationError.msg);
156
131
  }
157
132
 
158
- const sign = crypto.createHash('sha256').update(requestBody + token).digest('hex');
159
- const apiUrl = buildApiUrl(baseUrl, WORK_TIME_RECORD_LIST_API_URL);
160
- const headers = Object.assign({
161
- 'Content-Type': 'application/json;charset=UTF-8',
162
- sign,
163
- }, userId ? { userId } : {});
164
- if (debug) {
165
- process.stderr.write(`[debug] URL: ${apiUrl}\n[debug] Headers: ${JSON.stringify(headers)}\n[debug] RequestBody: ${requestBody}\n`);
166
- }
167
- const resp = await fetch(apiUrl, {
168
- method: 'POST',
169
- headers,
170
- body: requestBody,
133
+ const gateway = await requestGateway({
134
+ baseUrl,
135
+ apiPath: WORK_TIME_RECORD_LIST_API_PATH,
136
+ payload,
137
+ token,
138
+ userId,
139
+ debug,
171
140
  });
172
-
173
- if (!resp.ok) {
174
- const responseText = await resp.text();
175
- if (debug) process.stderr.write(`[debug] ResponseBody: ${responseText}\n`);
176
- return makeErrorRow(resp.status, `HTTP ${resp.status} ${resp.statusText}`);
177
- }
178
-
179
- const data = await resp.json();
180
- lastPagination = data?.code === 1 && data?.result?.totalCount != null && data?.result?.totalPage != null
181
- ? { totalCount: data.result.totalCount, totalPage: data.result.totalPage }
182
- : null;
183
- const responseBody = JSON.stringify(data);
184
- if (debug) process.stderr.write(`[debug] ResponseBody: ${responseBody}\n`);
185
- if (data.code !== 1) {
186
- return makeErrorRow(data.code ?? '', data.msg ?? '未知错误');
141
+ if (!gateway.ok) return makeErrorRow(gateway.code, gateway.msg);
142
+ pagination.update(gateway.data);
143
+ if (kwargs.raw) return [{ raw: gateway.responseBody }];
144
+ if (gateway.data.code !== 1) {
145
+ return makeErrorRow(gateway.data.code ?? '', gateway.data.msg ?? '未知错误');
187
146
  }
188
147
 
189
- const list = Array.isArray(data.result?.list) ? data.result.list : [];
148
+ const list = Array.isArray(gateway.data.result?.list) ? gateway.data.result.list : [];
190
149
  if (!list.length) {
191
150
  return makeErrorRow('NO_DATA', '接口成功,但 list 为空');
192
151
  }
package/xbb-http.js ADDED
@@ -0,0 +1,71 @@
1
+ import crypto from 'node:crypto';
2
+ import { readActiveConfig } from './xbb-config.js';
3
+
4
+ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
5
+
6
+ // 业务命令统一的运行时配置:从 config.env 读取 enable=true 的公司并规范化字段
7
+ export function getRuntimeConfig() {
8
+ const config = readActiveConfig();
9
+ return {
10
+ corpid: String(config.corpid || '').trim(),
11
+ token: String(config.token || '').trim(),
12
+ baseUrl: String(config.baseurl || DEFAULT_BASE_URL).trim(),
13
+ userId: String(config.userId || '').trim(),
14
+ };
15
+ }
16
+
17
+ // 网关 POST:序列化、SHA256 签名、headers 组装、debug 输出与 HTTP 层错误处理
18
+ // 成功返回 { ok: true, data, responseBody };HTTP 失败返回 { ok: false, code, msg }
19
+ export async function requestGateway({ baseUrl, apiPath, payload, token, userId, debug }) {
20
+ const body = JSON.stringify(payload);
21
+ const sign = crypto.createHash('sha256').update(body + token).digest('hex');
22
+ const headers = Object.assign(
23
+ { 'Content-Type': 'application/json;charset=UTF-8', sign },
24
+ userId ? { userId } : {},
25
+ );
26
+ const apiUrl = `${String(baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, '')}${apiPath}`;
27
+
28
+ if (debug) {
29
+ process.stderr.write(`[debug] URL: ${apiUrl}\n[debug] Headers: ${JSON.stringify(headers)}\n[debug] RequestBody: ${body}\n`);
30
+ }
31
+
32
+ const resp = await fetch(apiUrl, {
33
+ method: 'POST',
34
+ headers,
35
+ body,
36
+ });
37
+
38
+ if (!resp.ok) {
39
+ const responseText = await resp.text();
40
+ if (debug) process.stderr.write(`[debug] ResponseBody: ${responseText}\n`);
41
+ return { ok: false, code: resp.status, msg: `HTTP ${resp.status} ${resp.statusText}` };
42
+ }
43
+
44
+ const data = await resp.json();
45
+ const responseBody = JSON.stringify(data);
46
+ if (debug) process.stderr.write(`[debug] ResponseBody: ${responseBody}\n`);
47
+ return { ok: true, data, responseBody };
48
+ }
49
+
50
+ // 分页 footer 骨架:update(data) 记录 totalCount/totalPage,footerExtra 交给 cli()
51
+ // countOnly 用于只有顶层 totalCount 的接口(orginal-text-list 变体)
52
+ export function createPagination({ countOnly = false } = {}) {
53
+ let state = null;
54
+ return {
55
+ update(data) {
56
+ const result = data?.result;
57
+ const totalCount = countOnly
58
+ ? (data?.totalCount ?? result?.totalCount)
59
+ : (result?.totalCount ?? data?.totalCount);
60
+ const totalPage = countOnly ? undefined : (result?.totalPage ?? data?.totalPage);
61
+ const valid = data?.code === 1 && totalCount != null && (countOnly || totalPage != null);
62
+ state = valid ? { totalCount, totalPage } : null;
63
+ },
64
+ footerExtra() {
65
+ if (!state) return undefined;
66
+ return countOnly
67
+ ? `totalCount ${state.totalCount}`
68
+ : `totalCount ${state.totalCount} / totalPage ${state.totalPage}`;
69
+ },
70
+ };
71
+ }