@besile/scm-cli 2026.3.29
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.zh.md +451 -0
- package/bin/scm-cli.js +38 -0
- package/index.d.ts +59 -0
- package/package.json +51 -0
- package/src/cmd/auth/login.js +92 -0
- package/src/cmd/auth/logout.js +39 -0
- package/src/cmd/auth/status.js +29 -0
- package/src/cmd/auth/token.js +118 -0
- package/src/cmd/index.js +40 -0
- package/src/cmd/orders/material-orders.js +123 -0
- package/src/cmd/orders/production-orders.js +143 -0
- package/src/cmd/orders/qc-orders.js +109 -0
- package/src/cmd/root.js +41 -0
- package/src/core/scm-client.js +8 -0
- package/src/core/scm-errors.js +20 -0
- package/src/core/scm-logger.js +18 -0
- package/src/internal/auth/token-store.js +155 -0
- package/src/internal/client/scm-client.js +420 -0
- package/src/internal/config/config.js +62 -0
- package/src/internal/errors/scm-errors.js +140 -0
- package/src/internal/index.js +43 -0
- package/src/internal/output/formatter.js +120 -0
- package/src/internal/output/logger.js +168 -0
- package/src/shortcuts/common/runner.js +145 -0
- package/src/shortcuts/common/types.js +35 -0
- package/src/shortcuts/index.js +23 -0
- package/src/shortcuts/material-orders/index.js +12 -0
- package/src/shortcuts/material-orders/list.js +77 -0
- package/src/shortcuts/production-orders/index.js +13 -0
- package/src/shortcuts/production-orders/list.js +48 -0
- package/src/shortcuts/production-orders/query.js +86 -0
- package/src/shortcuts/qc-orders/index.js +12 -0
- package/src/shortcuts/qc-orders/list.js +79 -0
- package/src/shortcuts/register.js +82 -0
package/README.zh.md
ADDED
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
# SCM CLI
|
|
2
|
+
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://nodejs.org/)
|
|
5
|
+
|
|
6
|
+
供应链管理(SCM)系统 CLI 工具 — 在终端中查询大货生产订单、物料订单和 QC 质检订单,对接飞书身份认证系统。
|
|
7
|
+
|
|
8
|
+
[安装](#安装与快速开始) · [认证](#认证) · [三层命令调用](#三层命令调用) · [快捷命令](#快捷命令-shortcuts) · [进阶用法](#进阶用法) · [安全](#安全与风险提示使用前必读) · [贡献](#贡献)
|
|
9
|
+
|
|
10
|
+
## 为什么选 scm-cli?
|
|
11
|
+
|
|
12
|
+
- **飞书身份集成** — 基于飞书 openId 认证,无需记忆额外账号密码
|
|
13
|
+
- **三分钟上手** — 一键安装,交互式登录,从安装到第一次查询只需三步
|
|
14
|
+
- **双层调用架构** — 标准命令(全面控制)→ 快捷命令(快速上手),按需选择
|
|
15
|
+
- **AES 加密存储** — 用户密码和 Token 均加密存储于本地
|
|
16
|
+
- **多格式输出** — 支持 table / json / pretty 三种输出格式
|
|
17
|
+
- **Token 自动续期** — 缓存 Token 自动检查,过期前无缝续期
|
|
18
|
+
|
|
19
|
+
## 功能
|
|
20
|
+
|
|
21
|
+
| 类别 | 能力 |
|
|
22
|
+
| -------------- | -------------------------------------------------------------------- |
|
|
23
|
+
| 🔐 认证管理 | 登录、登出、Token 状态检查、Token 列表管理 |
|
|
24
|
+
| 📦 大货生产订单 | 查询订单列表,支持订单状态、供应商、商品信息、时间、设计师等多维筛选 |
|
|
25
|
+
| 🧴 物料订单 | 查询物料订单,支持按订单号、大货款号、批次、供应商等条件筛选 |
|
|
26
|
+
| 🔍 QC 质检订单 | 查询 QC 质检订单,支持质检状态、款号、供应商、时间等筛选条件 |
|
|
27
|
+
|
|
28
|
+
## 安装与快速开始
|
|
29
|
+
|
|
30
|
+
### 环境要求
|
|
31
|
+
|
|
32
|
+
- Node.js(`npm`/`npx`)14+
|
|
33
|
+
- SCM API 服务地址(配置方式见下文)
|
|
34
|
+
|
|
35
|
+
### 安装
|
|
36
|
+
|
|
37
|
+
以下两种方式**任选其一**:
|
|
38
|
+
|
|
39
|
+
**方式一 — 从源码安装(推荐):**
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git clone <your-repo-url>
|
|
43
|
+
cd scm-cli
|
|
44
|
+
./install.sh
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**方式二 — 手动安装:**
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# 克隆项目
|
|
51
|
+
git clone <your-repo-url>
|
|
52
|
+
cd scm-cli
|
|
53
|
+
|
|
54
|
+
# 安装依赖
|
|
55
|
+
npm install
|
|
56
|
+
|
|
57
|
+
# 链接到全局
|
|
58
|
+
npm link
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### 验证安装
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
scm-cli --help
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 配置
|
|
68
|
+
|
|
69
|
+
安装完成后,需要配置环境变量才能连接 SCM API:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# 方式一:创建 .env 文件(项目根目录)
|
|
73
|
+
cp .env.example .env
|
|
74
|
+
# 编辑 .env 填入以下配置
|
|
75
|
+
|
|
76
|
+
# 方式二:直接设置环境变量
|
|
77
|
+
export SCM_BASE_URL=http://localhost:48080
|
|
78
|
+
export SCM_DEBUG=false
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**可选的环境变量:**
|
|
82
|
+
|
|
83
|
+
| 变量 | 说明 | 默认值 |
|
|
84
|
+
| -------------- | ----------------------------- | ------------------------------------- |
|
|
85
|
+
| `SCM_BASE_URL` | SCM API 端点地址(**必需**) | `https://fbscmtest.cogo.club` |
|
|
86
|
+
| `SCM_DEBUG` | 开启调试模式 | `false` |
|
|
87
|
+
|
|
88
|
+
> **说明**:`SCM_AES_KEY` 和 `SCM_AES_IV` 已内置于代码中,无需配置。如需自定义加密密钥,请联系 SCM 系统管理员。
|
|
89
|
+
|
|
90
|
+
### 快速开始
|
|
91
|
+
|
|
92
|
+
**第 1 步 — 登录**
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
scm-cli auth login \
|
|
96
|
+
--openId <飞书openId> \
|
|
97
|
+
--mobile <手机号> \
|
|
98
|
+
--password <密码>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**第 2 步 — 查询大货生产订单**
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# 标准命令
|
|
105
|
+
scm-cli production-orders --openId <openId> --pageSize 20
|
|
106
|
+
|
|
107
|
+
# 快捷命令(更简洁)
|
|
108
|
+
scm-cli production-orders +list --openId <openId>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**第 3 步 — 查看帮助**
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
scm-cli --help
|
|
115
|
+
scm-cli auth --help
|
|
116
|
+
scm-cli production-orders --help
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## 认证
|
|
120
|
+
|
|
121
|
+
| 命令 | 说明 |
|
|
122
|
+
| ------------------------------ | ------------------------------------ |
|
|
123
|
+
| `auth login` | 登录 SCM 系统(基于飞书身份) |
|
|
124
|
+
| `auth logout` | 登出,删除本地 Token |
|
|
125
|
+
| `auth status` | 检查 Token 状态 |
|
|
126
|
+
| `auth token list` | 列出所有缓存的 Token |
|
|
127
|
+
| `auth token show <openId>` | 显示指定用户的 Token 详情 |
|
|
128
|
+
| `auth token clear <openId>` | 清除指定用户的 Token |
|
|
129
|
+
| `auth token clear-all` | 清除所有缓存的 Token |
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# 登录
|
|
133
|
+
scm-cli auth login --openId ou_xxxx --mobile 13800138000 --password 123456
|
|
134
|
+
|
|
135
|
+
# 检查 Token 状态
|
|
136
|
+
scm-cli auth status --openId ou_xxxx
|
|
137
|
+
|
|
138
|
+
# 查看所有缓存的 Token
|
|
139
|
+
scm-cli auth token list
|
|
140
|
+
|
|
141
|
+
# 登出
|
|
142
|
+
scm-cli auth logout --openId ou_xxxx
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Token 存储
|
|
146
|
+
|
|
147
|
+
- Token 缓存路径:`~/.scm_cache/user_tokens.json`
|
|
148
|
+
- 密码使用 **AES-128-CBC** 加密后再传输和存储
|
|
149
|
+
- Token 有效期约 12 小时,过期前自动刷新
|
|
150
|
+
|
|
151
|
+
## 三层命令调用
|
|
152
|
+
|
|
153
|
+
CLI 提供两种粒度的调用方式,覆盖从快速查询到精确筛选的全部场景:
|
|
154
|
+
|
|
155
|
+
### 1. 标准命令
|
|
156
|
+
|
|
157
|
+
标准命令提供最完整的筛选参数集,适合需要精确控制查询条件的场景:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# 大货生产订单 — 所有筛选参数
|
|
161
|
+
scm-cli production-orders \
|
|
162
|
+
--openId <openId> \
|
|
163
|
+
--pageNo 1 \
|
|
164
|
+
--pageSize 20 \
|
|
165
|
+
--prodStatus 3 \
|
|
166
|
+
--confirmSupplier 1 \
|
|
167
|
+
--supplierOrderStatus 1 \
|
|
168
|
+
--quotationStatus 2 \
|
|
169
|
+
--washStatus 1 \
|
|
170
|
+
--qcInspection 1 \
|
|
171
|
+
--goodsFullCode "款号001" \
|
|
172
|
+
--goodsBatch "批次001" \
|
|
173
|
+
--goodsType 0 \
|
|
174
|
+
--supplierName "某供应商" \
|
|
175
|
+
--cooperationMode 0 \
|
|
176
|
+
--pdUserIdList "1,2,3" \
|
|
177
|
+
--purchaserIdList "4,5,6" \
|
|
178
|
+
--designerName "设计师A" \
|
|
179
|
+
--type 2 \
|
|
180
|
+
--startTime "2026-01-01" \
|
|
181
|
+
--endTime "2026-12-31" \
|
|
182
|
+
--saleArea "1,2,3"
|
|
183
|
+
|
|
184
|
+
# 物料订单 — 所有筛选参数
|
|
185
|
+
scm-cli material-orders \
|
|
186
|
+
--openId <openId> \
|
|
187
|
+
--pageNo 1 \
|
|
188
|
+
--pageSize 20 \
|
|
189
|
+
--orderNo "MO202603001" \
|
|
190
|
+
--status 1 \
|
|
191
|
+
--cooperationMode 0 \
|
|
192
|
+
--goodsFullCode "款号001" \
|
|
193
|
+
--goodsBatch "批次001" \
|
|
194
|
+
--goodsType 0 \
|
|
195
|
+
--supplierName "某供应商" \
|
|
196
|
+
--purchaserIdList "4,5,6" \
|
|
197
|
+
--pdUserIdList "1,2,3" \
|
|
198
|
+
--designerName "设计师A" \
|
|
199
|
+
--type 2 \
|
|
200
|
+
--startTime "2026-01-01" \
|
|
201
|
+
--endTime "2026-12-31"
|
|
202
|
+
|
|
203
|
+
# QC 质检订单 — 所有筛选参数
|
|
204
|
+
scm-cli qc-orders \
|
|
205
|
+
--openId <openId> \
|
|
206
|
+
--pageNo 1 \
|
|
207
|
+
--pageSize 20 \
|
|
208
|
+
--qcOrderStatus 1 \
|
|
209
|
+
--goodsFullCode "款号001" \
|
|
210
|
+
--goodsType 1 \
|
|
211
|
+
--goodsGradeList "A,B" \
|
|
212
|
+
--supplierName "某供应商" \
|
|
213
|
+
--midManager "中查管理员A" \
|
|
214
|
+
--checkGoods "查货人员B" \
|
|
215
|
+
--tailManager "尾查管理员C" \
|
|
216
|
+
--qcUserIdList "1,2,3" \
|
|
217
|
+
--prodManagerIdList "4,5,6" \
|
|
218
|
+
--purchaserIdList "7,8,9" \
|
|
219
|
+
--timeType 2 \
|
|
220
|
+
--startTime "2026-01-01" \
|
|
221
|
+
--endTime "2026-12-31"
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### 2. 快捷命令(Shortcuts)
|
|
225
|
+
|
|
226
|
+
以 `+` 为前缀,是对人机友好化封装,内置智能默认值,适合快速查询:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
# 大货生产订单 — 列表查询
|
|
230
|
+
scm-cli production-orders +list --openId <openId>
|
|
231
|
+
|
|
232
|
+
# 大货生产订单 — 高级查询
|
|
233
|
+
scm-cli production-orders +query \
|
|
234
|
+
--openId <openId> \
|
|
235
|
+
--prod-status 3 \
|
|
236
|
+
--supplier-name "某供应商"
|
|
237
|
+
|
|
238
|
+
# 物料订单 — 列表查询
|
|
239
|
+
scm-cli material-orders +list --openId <openId>
|
|
240
|
+
|
|
241
|
+
# QC 质检订单 — 列表查询
|
|
242
|
+
scm-cli qc-orders +list --openId <openId>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## 快捷命令(Shortcuts)
|
|
246
|
+
|
|
247
|
+
| 命令 | 说明 |
|
|
248
|
+
| ------------------------------ | ------------------------------------------ |
|
|
249
|
+
| `production-orders +list` | 查询大货生产订单列表(分页,默认 20 条/页) |
|
|
250
|
+
| `production-orders +query` | 查询大货生产订单(支持全部筛选条件) |
|
|
251
|
+
| `material-orders +list` | 查询物料订单列表(分页) |
|
|
252
|
+
| `qc-orders +list` | 查询 QC 质检订单列表(分页) |
|
|
253
|
+
|
|
254
|
+
### 生产订单快捷命令详解
|
|
255
|
+
|
|
256
|
+
**`+list` — 快速列表查询**
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
scm-cli production-orders +list \
|
|
260
|
+
--open-id <openId> \
|
|
261
|
+
[--page-no 1] \
|
|
262
|
+
[--page-size 20]
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**`+query` — 完整条件查询**
|
|
266
|
+
|
|
267
|
+
支持以下所有筛选参数:
|
|
268
|
+
|
|
269
|
+
| 参数 | 说明 |
|
|
270
|
+
| --------------------- | --------------------------------------------------------------------- |
|
|
271
|
+
| `--prod-status` | 大货生产订单状态: `-1`-全部`0`-待确定`1`-待同步`2`-在途中`3`-已完成`100`-已取消 |
|
|
272
|
+
| `--confirm-supplier` | 确认供应商: `0`-未确认`1`-已确认 |
|
|
273
|
+
| `--goods-full-code` | 大货款号 |
|
|
274
|
+
| `--goods-batch` | 大货批次 |
|
|
275
|
+
| `--goods-type` | 大货类型: `0`-首单`1`-加单`2`-翻单 |
|
|
276
|
+
| `--supplier-name` | 供应商名称 |
|
|
277
|
+
| `--cooperation-mode` | 合作模式: `0`-CMT`1`-FOB |
|
|
278
|
+
| `--designer-name` | 设计师名称 |
|
|
279
|
+
| `--start-time` / `--end-time` | 时间范围 (ISO 8601) |
|
|
280
|
+
| `--qc-inspection` | QC 质检结果 |
|
|
281
|
+
|
|
282
|
+
### 物料订单快捷命令详解
|
|
283
|
+
|
|
284
|
+
**`+list` — 物料订单列表**
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
scm-cli material-orders +list \
|
|
288
|
+
--open-id <openId> \
|
|
289
|
+
[--page-no 1] \
|
|
290
|
+
[--page-size 20] \
|
|
291
|
+
[--order-no <订单号>] \
|
|
292
|
+
[--goods-full-code <款号>] \
|
|
293
|
+
[--goods-batch <批次>] \
|
|
294
|
+
[--goods-type <类型>] \
|
|
295
|
+
[--supplier-name <供应商名>] \
|
|
296
|
+
[--status <状态值>]
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### QC 质检订单快捷命令详解
|
|
300
|
+
|
|
301
|
+
**`+list` — QC 质检订单列表**
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
scm-cli qc-orders +list \
|
|
305
|
+
--open-id <openId> \
|
|
306
|
+
[--page-no 1] \
|
|
307
|
+
[--page-size 10] \
|
|
308
|
+
[--qc-order-status <状态值>] \
|
|
309
|
+
[--goods-full-code <款号>] \
|
|
310
|
+
[--goods-type <类型>] \
|
|
311
|
+
[--supplier-name <供应商名>] \
|
|
312
|
+
[--mid-manager <中查管理员>] \
|
|
313
|
+
[--check-goods <查货人员>] \
|
|
314
|
+
[--tail-manager <尾查管理员>] \
|
|
315
|
+
[--qc-user-id-list <QC用户ID列表>] \
|
|
316
|
+
[--prod-manager-id-list <生产经理ID列表>] \
|
|
317
|
+
[--purchaser-id-list <采购员ID列表>] \
|
|
318
|
+
[--time-type <时间类型>] \
|
|
319
|
+
[--start-time <开始时间>] \
|
|
320
|
+
[--end-time <结束时间>]
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## 进阶用法
|
|
324
|
+
|
|
325
|
+
### 输出格式
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
--format json # 完整 JSON 响应(API 原生格式)
|
|
329
|
+
--format pretty # 人性化格式输出
|
|
330
|
+
--format table # 易读表格(默认)
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
# 输出 JSON
|
|
335
|
+
scm-cli production-orders +list --openId ou_xxxx --format json
|
|
336
|
+
|
|
337
|
+
# 输出易读格式
|
|
338
|
+
scm-cli material-orders +list --openId ou_xxxx --format pretty
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### 调试模式
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
# 全局调试
|
|
345
|
+
scm-cli --debug production-orders +list --openId ou_xxxx
|
|
346
|
+
|
|
347
|
+
# 或设置环境变量
|
|
348
|
+
export SCM_DEBUG=true
|
|
349
|
+
scm-cli production-orders +list --openId ou_xxxx
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### 常用查询示例
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
# 查询生产中(状态=3)的订单
|
|
356
|
+
scm-cli production-orders +query \
|
|
357
|
+
--open-id ou_xxxx \
|
|
358
|
+
--prod-status 3 \
|
|
359
|
+
--page-size 50
|
|
360
|
+
|
|
361
|
+
# 查询指定供应商的所有物料订单
|
|
362
|
+
scm-cli material-orders +list \
|
|
363
|
+
--open-id ou_xxxx \
|
|
364
|
+
--supplier-name "某服装厂"
|
|
365
|
+
|
|
366
|
+
# 查询 QC 待检订单
|
|
367
|
+
scm-cli qc-orders +list \
|
|
368
|
+
--open-id ou_xxxx \
|
|
369
|
+
--qc-order-status 0
|
|
370
|
+
|
|
371
|
+
# 按时间范围查询(近一个月)
|
|
372
|
+
scm-cli production-orders +query \
|
|
373
|
+
--open-id ou_xxxx \
|
|
374
|
+
--start-time "2026-03-01" \
|
|
375
|
+
--end-time "2026-04-13"
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## 安全与风险提示(使用前必读)
|
|
379
|
+
|
|
380
|
+
本工具对接 SCM 供应链管理系统,涉及生产订单、物料采购等商业敏感数据。请在使用前充分知悉以下风险:
|
|
381
|
+
|
|
382
|
+
**认证风险** — Token 缓存于本地文件,密码通过 AES-128-CBC 加密存储,请勿将本工具暴露于不受信任的环境。
|
|
383
|
+
|
|
384
|
+
**数据安全** — Token 有效期约 12 小时,过期后需要重新认证。请勿将 Token 或配置文件泄露给他人。
|
|
385
|
+
|
|
386
|
+
**权限管控** — 所有操作权限取决于飞书账号的 SCM 系统授权范围,请按最小权限原则分配飞书身份。
|
|
387
|
+
|
|
388
|
+
请您充分知悉全部使用风险,使用本工具即视为您自愿承担相关所有责任。
|
|
389
|
+
|
|
390
|
+
## 项目结构
|
|
391
|
+
|
|
392
|
+
```
|
|
393
|
+
scm-cli/
|
|
394
|
+
├── bin/
|
|
395
|
+
│ └── scm-cli.js # CLI 入口点
|
|
396
|
+
├── src/
|
|
397
|
+
│ ├── cmd/ # Layer 1: Commander 命令注册
|
|
398
|
+
│ │ ├── root.js # 根命令 + 全局参数(--format, --debug)
|
|
399
|
+
│ │ ├── index.js # 注册所有子命令
|
|
400
|
+
│ │ ├── auth/ # 认证子命令
|
|
401
|
+
│ │ │ ├── login.js # 登录
|
|
402
|
+
│ │ │ ├── logout.js # 登出
|
|
403
|
+
│ │ │ ├── status.js # Token 状态检查
|
|
404
|
+
│ │ │ └── token.js # Token 管理(列表/清除)
|
|
405
|
+
│ │ └── orders/ # 订单子命令
|
|
406
|
+
│ │ ├── production-orders.js
|
|
407
|
+
│ │ ├── material-orders.js
|
|
408
|
+
│ │ └── qc-orders.js
|
|
409
|
+
│ ├── shortcuts/ # Layer 2: 快捷命令(Shortcuts)
|
|
410
|
+
│ │ ├── common/
|
|
411
|
+
│ │ │ ├── types.js # Shortcut 类型定义
|
|
412
|
+
│ │ │ └── runner.js # Shortcut 执行管道
|
|
413
|
+
│ │ ├── register.js # 注册 Shortcuts 到命令树
|
|
414
|
+
│ │ ├── production-orders/ # +list, +query 快捷命令
|
|
415
|
+
│ │ ├── material-orders/ # +list 快捷命令
|
|
416
|
+
│ │ └── qc-orders/ # +list 快捷命令
|
|
417
|
+
│ └── internal/ # Layer 3: 核心库
|
|
418
|
+
│ ├── index.js # 统一导出
|
|
419
|
+
│ ├── client/ # ScmClient 单例
|
|
420
|
+
│ ├── errors/ # 错误类层次结构
|
|
421
|
+
│ ├── output/ # 格式化输出 + 日志
|
|
422
|
+
│ ├── config/ # 配置文件加载
|
|
423
|
+
│ └── auth/ # Token 存储与认证
|
|
424
|
+
├── tests/ # 测试用例
|
|
425
|
+
├── install.sh # 安装脚本
|
|
426
|
+
└── package.json
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## 开发
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
# 安装依赖
|
|
433
|
+
npm install
|
|
434
|
+
|
|
435
|
+
# 运行测试
|
|
436
|
+
npm test
|
|
437
|
+
|
|
438
|
+
# 监听模式运行测试
|
|
439
|
+
npm run test:watch
|
|
440
|
+
|
|
441
|
+
# 带覆盖率运行测试
|
|
442
|
+
npm run test:coverage
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## 贡献
|
|
446
|
+
|
|
447
|
+
欢迎提交 Issue 或 Pull Request!对于较大的改动,建议先通过 Issue 讨论。
|
|
448
|
+
|
|
449
|
+
## 许可证
|
|
450
|
+
|
|
451
|
+
本项目基于 **MIT 许可证** 开源。
|
package/bin/scm-cli.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Copyright (c) 2026 WFS
|
|
5
|
+
* SPDX-License-Identifier: MIT
|
|
6
|
+
*
|
|
7
|
+
* scm-cli — SCM CLI 工具入口
|
|
8
|
+
*
|
|
9
|
+
* 用法:
|
|
10
|
+
* scm-cli --help
|
|
11
|
+
* scm-cli auth login --openId <openId> --mobile <手机号> --password <密码>
|
|
12
|
+
* scm-cli auth logout --openId <openId>
|
|
13
|
+
* scm-cli auth status --openId <openId>
|
|
14
|
+
* scm-cli production-orders --openId <openId> [--goodsFullCode <款号>]
|
|
15
|
+
* scm-cli material-orders --openId <openId> [--orderNo <订单号>]
|
|
16
|
+
* scm-cli qc-orders --openId <openId> [--qcOrderStatus <状态>]
|
|
17
|
+
* scm-cli production-orders +list --openId <openId> [--format table]
|
|
18
|
+
* scm-cli production-orders +query --openId <openId> [--prod-status 3]
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { readFileSync } from 'node:fs';
|
|
22
|
+
import { join, dirname } from 'node:path';
|
|
23
|
+
import { fileURLToPath } from 'node:url';
|
|
24
|
+
import { createProgram, buildInternalContext } from '../src/cmd/root.js';
|
|
25
|
+
import { registerCommands } from '../src/cmd/index.js';
|
|
26
|
+
|
|
27
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
28
|
+
const __dirname = dirname(__filename);
|
|
29
|
+
const projectRoot = dirname(__dirname);
|
|
30
|
+
|
|
31
|
+
const { version } = JSON.parse(readFileSync(join(projectRoot, 'package.json'), 'utf-8'));
|
|
32
|
+
|
|
33
|
+
const program = createProgram({ version, name: 'scm-cli' });
|
|
34
|
+
const internalCtx = buildInternalContext({ debug: process.env.SCM_DEBUG === 'true' });
|
|
35
|
+
|
|
36
|
+
registerCommands(program, internalCtx);
|
|
37
|
+
|
|
38
|
+
program.parse();
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 WFS
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* OpenClaw SCM Plugin entry point.
|
|
6
|
+
*
|
|
7
|
+
* SCM 供应链管理插件入口
|
|
8
|
+
*
|
|
9
|
+
* 注册工具:
|
|
10
|
+
* - scm_login: 登录认证
|
|
11
|
+
* - scm_production_orders: 大货生产订单查询
|
|
12
|
+
* - scm_material_orders: 物料订单查询
|
|
13
|
+
* - scm_qc_orders: QC 质检订单查询
|
|
14
|
+
*/
|
|
15
|
+
import type { OpenClawPluginApi } from 'openclaw/plugin-sdk';
|
|
16
|
+
|
|
17
|
+
// SCM 客户端
|
|
18
|
+
export { scmClient } from './src/core/scm-client';
|
|
19
|
+
|
|
20
|
+
// SCM 错误类
|
|
21
|
+
export { ScmError, ScmAuthError, ScmTokenExpiredError, ScmTokenInvalidError, ScmApiError, ScmTimeoutError, ScmNetworkError } from './src/core/scm-errors';
|
|
22
|
+
export type { ScmErrorOptions, ScmApiErrorOptions } from './src/core/scm-errors';
|
|
23
|
+
|
|
24
|
+
// 工具执行函数 - scm_login
|
|
25
|
+
export { executeScmLogin } from './src/tools/login/execute';
|
|
26
|
+
|
|
27
|
+
// 工具执行函数 - scm_production_orders
|
|
28
|
+
export { executeProductionOrders } from './src/tools/production-orders/execute';
|
|
29
|
+
|
|
30
|
+
// 工具执行函数 - scm_material_orders
|
|
31
|
+
export { executeMaterialOrders } from './src/tools/material-orders/execute';
|
|
32
|
+
|
|
33
|
+
// 工具执行函数 - scm_qc_orders
|
|
34
|
+
export { executeQcOrders, buildRequestBody as buildQcOrdersRequestBody } from './src/tools/qc-orders/execute';
|
|
35
|
+
|
|
36
|
+
// 工具注册函数
|
|
37
|
+
export { registerScmLoginTool } from './src/tools/login/index';
|
|
38
|
+
export { registerScmProductionOrdersTool } from './src/tools/production-orders/index';
|
|
39
|
+
export { registerScmMaterialOrdersTool } from './src/tools/material-orders/index';
|
|
40
|
+
export { registerScmQcOrdersTool } from './src/tools/qc-orders/index';
|
|
41
|
+
|
|
42
|
+
// SCM 插件 Channel
|
|
43
|
+
export { scmPlugin } from './src/channel/plugin';
|
|
44
|
+
|
|
45
|
+
// 工具辅助函数
|
|
46
|
+
export { createToolContext, formatResult, formatSuccess, formatError, formatApiError, getUserToken, clearUserToken } from './src/tools/helpers';
|
|
47
|
+
export type { ToolContext } from './src/tools/helpers';
|
|
48
|
+
|
|
49
|
+
// 日志辅助函数
|
|
50
|
+
export { scmLogger, setRuntimeLoggerFactory } from './src/core/scm-logger';
|
|
51
|
+
|
|
52
|
+
declare const plugin: {
|
|
53
|
+
id: string;
|
|
54
|
+
name: string;
|
|
55
|
+
description: string;
|
|
56
|
+
configSchema: Record<string, unknown>;
|
|
57
|
+
register(api: OpenClawPluginApi): void;
|
|
58
|
+
};
|
|
59
|
+
export default plugin;
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@besile/scm-cli",
|
|
3
|
+
"version": "2026.3.29",
|
|
4
|
+
"description": "SCM CLI — Supply Chain Management CLI Tool",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "WFS",
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=18.0.0"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/wfs/scm-cli"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"scm",
|
|
17
|
+
"supply-chain",
|
|
18
|
+
"cli",
|
|
19
|
+
"production-order",
|
|
20
|
+
"manufacturing"
|
|
21
|
+
],
|
|
22
|
+
"files": [
|
|
23
|
+
"bin/",
|
|
24
|
+
"src/",
|
|
25
|
+
"index.d.ts"
|
|
26
|
+
],
|
|
27
|
+
"bin": {
|
|
28
|
+
"scm-cli": "./bin/scm-cli.js"
|
|
29
|
+
},
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"import": "./src/internal/index.js",
|
|
33
|
+
"default": "./src/internal/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"test:watch": "vitest",
|
|
39
|
+
"test:coverage": "vitest run --coverage"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@larksuiteoapi/node-sdk": "^1.7.0",
|
|
43
|
+
"@sinclair/typebox": "^0.34.48",
|
|
44
|
+
"commander": "^14.0.3",
|
|
45
|
+
"dotenv": "^17.3.1"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@vitest/coverage-v8": "^2.1.9",
|
|
49
|
+
"vitest": "^2.0.0"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 WFS
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* scm-cli auth login command
|
|
7
|
+
*/
|
|
8
|
+
import { scmClient, loadConfig, createLogger } from '../../internal/index.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Execute login
|
|
12
|
+
*
|
|
13
|
+
* @param {string} openId - 飞书用户 openId
|
|
14
|
+
* @param {string} mobile - 手机号
|
|
15
|
+
* @param {string} password - 密码
|
|
16
|
+
* @returns {Promise<Object>} Login result
|
|
17
|
+
*/
|
|
18
|
+
export async function doLogin(openId, mobile, password) {
|
|
19
|
+
const config = loadConfig();
|
|
20
|
+
const log = createLogger(config.debug);
|
|
21
|
+
|
|
22
|
+
// Encrypt password with AES-128-CBC
|
|
23
|
+
const { createCipheriv } = await import('node:crypto');
|
|
24
|
+
const cipher = createCipheriv(
|
|
25
|
+
'aes-128-cbc',
|
|
26
|
+
Buffer.from(config.aesKey, 'ascii'),
|
|
27
|
+
Buffer.from(config.aesIv, 'ascii')
|
|
28
|
+
);
|
|
29
|
+
const encrypted = Buffer.concat([
|
|
30
|
+
cipher.update(Buffer.from(password, 'utf-8')),
|
|
31
|
+
cipher.final(),
|
|
32
|
+
]).toString('base64');
|
|
33
|
+
|
|
34
|
+
const loginUrl = `${config.baseUrl}/admin-api/system/auth/login`;
|
|
35
|
+
|
|
36
|
+
const response = await fetch(loginUrl, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers: { 'Content-Type': 'application/json' },
|
|
39
|
+
body: JSON.stringify({ mobile, password: encrypted }),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const data = await response.json();
|
|
43
|
+
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (data.code !== 200 && data.success !== true) {
|
|
49
|
+
throw new Error(data.msg || `登录失败,错误码: ${data.code}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const tokenInfo = data.data || {};
|
|
53
|
+
return {
|
|
54
|
+
openId,
|
|
55
|
+
mobile,
|
|
56
|
+
username: tokenInfo.username || mobile,
|
|
57
|
+
userId: tokenInfo.userId || '',
|
|
58
|
+
expiresIn: tokenInfo.expires_in || 12 * 3600,
|
|
59
|
+
accessToken: tokenInfo.access_token || tokenInfo.token,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Register auth login subcommand
|
|
65
|
+
*/
|
|
66
|
+
export function loginCommand(program) {
|
|
67
|
+
program
|
|
68
|
+
.command('login')
|
|
69
|
+
.description('登录 SCM 系统')
|
|
70
|
+
.requiredOption('--openId <openId>', '飞书用户 openId')
|
|
71
|
+
.requiredOption('--mobile <mobile>', '手机号(11位)')
|
|
72
|
+
.requiredOption('--password <password>', '密码')
|
|
73
|
+
.action(async (opts) => {
|
|
74
|
+
try {
|
|
75
|
+
console.log('正在登录 SCM...');
|
|
76
|
+
const result = await doLogin(opts.openId, opts.mobile, opts.password);
|
|
77
|
+
|
|
78
|
+
console.log('\n✅ 登录成功!');
|
|
79
|
+
console.log('───────────────');
|
|
80
|
+
console.log(`用户: ${result.username}`);
|
|
81
|
+
console.log(`User ID: ${result.userId}`);
|
|
82
|
+
console.log(`Open ID: ${result.openId}`);
|
|
83
|
+
console.log(`Token: ${result.accessToken.substring(0, 30)}...`);
|
|
84
|
+
console.log(`有效期: ${Math.round(result.expiresIn / 60)} 分钟`);
|
|
85
|
+
console.log('───────────────');
|
|
86
|
+
console.log('Token 已缓存到 ~/.scm_cache/user_tokens.json');
|
|
87
|
+
} catch (err) {
|
|
88
|
+
console.error('\n❌ 登录失败:', err.message);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|