@qinsilk/scm-agent-tools 0.0.0-stage → 0.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 +48 -2
- package/cli/api.js +114 -0
- package/cli/commands/data.js +112 -0
- package/cli/commands/docs.js +121 -0
- package/cli/commands/log.js +152 -0
- package/cli/commands/query.js +285 -0
- package/cli/commands/report.js +213 -0
- package/cli/commands/staff.js +505 -0
- package/cli/config.js +46 -0
- package/cli/datasets.js +541 -0
- package/cli/scm-agent.js +110 -0
- package/cli/skills.js +89 -0
- package/cli/table.js +43 -0
- package/docs/api.md +2067 -0
- package/docs/cli.md +252 -0
- package/package.json +27 -4
- package/reports/excel.js +107 -0
- package/reports/factoryEvaluation.js +128 -0
- package/reports/goodsBom.js +648 -0
- package/reports/goodsFirstOrder.js +409 -0
- package/reports/goodsInventory.js +220 -0
- package/reports/goodsSize.js +440 -0
- package/reports/image.js +216 -0
- package/reports/leakCheck.js +694 -0
- package/reports/materialPurchaseExport.js +393 -0
- package/reports/materialTransit.js +593 -0
- package/reports/processFollowup.js +312 -0
- package/reports/produceBoard.js +353 -0
- package/reports/produceCost.js +366 -0
- package/reports/produceCostDetail.js +622 -0
- package/reports/produceDaily.js +485 -0
- package/reports/storeInGoods.js +276 -0
- package/reports/supplierBalance.js +671 -0
- package/reports/ticketStatistics.js +289 -0
- package/reports/util.js +83 -0
- package/skills/bom/345/225/206/345/223/201/344/277/241/346/201/257/SKILL.md +40 -0
- package/skills/qinsilk-scm/SKILL.md +126 -0
- package/skills//344/276/233/345/272/224/345/225/206/345/257/271/350/264/246/345/257/274/345/207/272/SKILL.md +38 -0
- package/skills//345/225/206/345/223/201/345/260/272/345/257/270/344/277/241/346/201/257/SKILL.md +40 -0
- package/skills//345/225/206/345/223/201/351/246/226/345/215/225/351/235/242/346/226/231/345/267/245/345/272/217/345/215/225/344/273/267/SKILL.md +39 -0
- package/skills//345/267/245/345/216/202/350/257/204/344/274/260/346/212/245/350/241/250/SKILL.md +39 -0
- package/skills//346/210/220/345/223/201/345/205/245/345/272/223/346/212/245/350/241/250/SKILL.md +40 -0
- package/skills//346/234/215/350/243/205/346/210/220/345/223/201/347/233/230/345/255/230/350/241/250/SKILL.md +39 -0
- package/skills//346/274/217/346/226/231/346/243/200/346/265/213/346/227/245/346/212/245/SKILL.md +40 -0
- package/skills//347/211/251/346/226/231/345/234/250/351/200/224/347/212/266/346/200/201/346/212/245/350/241/250/SKILL.md +40 -0
- package/skills//347/211/251/346/226/231/351/207/207/350/264/255/345/257/274/345/207/272/SKILL.md +39 -0
- package/skills//347/224/237/344/272/247/345/215/225/345/267/245/345/272/217/350/267/237/350/277/233/350/241/250/SKILL.md +39 -0
- package/skills//347/224/237/344/272/247/346/210/220/346/234/254/346/212/245/350/241/250/SKILL.md +41 -0
- package/skills//347/224/237/344/272/247/346/210/220/346/234/254/346/212/245/350/241/250/346/230/216/347/273/206/SKILL.md +40 -0
- package/skills//347/224/237/344/272/247/346/227/245/346/212/245/SKILL.md +42 -0
- package/skills//347/224/237/344/272/247/347/212/266/345/206/265/347/273/237/350/256/241/350/241/250/SKILL.md +39 -0
- package/skills//347/224/237/344/272/247/350/212/202/347/202/271/347/234/213/346/235/277/SKILL.md +39 -0
package/docs/cli.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# scm-agent 全部命令说明(给你或你的 AI 看)
|
|
2
|
+
|
|
3
|
+
前置:已执行 `scm-agent login`(配置保存在 `~/.scm-agent/config.json`,权限 600)。
|
|
4
|
+
|
|
5
|
+
## 全局参数
|
|
6
|
+
|
|
7
|
+
| 参数 | 说明 |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `--json` | 以 JSON 输出结果(默认输出对齐表格) |
|
|
10
|
+
| `--page N` | 列表页码,从 1 开始(默认 1) |
|
|
11
|
+
| `--limit N` | 每页条数,最大 100(默认 20) |
|
|
12
|
+
|
|
13
|
+
## login — 配置 AI Key
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
scm-agent login --key qsk-xxxx [--server https://scm.qinsilk.com]
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
立即连接服务器验证 Key;成功输出企业/用户名并保存配置。失败不重试。`--server` 缺省生产地址;测试环境用 `https://devscm.qinsilk.com`。
|
|
20
|
+
|
|
21
|
+
## status — 验证配置
|
|
22
|
+
|
|
23
|
+
输出「生产ERP CLI 已配置完成,当前用户:企业 / 用户名(权限:数据只读)」。
|
|
24
|
+
|
|
25
|
+
## skills install — 安装技能
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
scm-agent skills install [--all]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
把包内全部官方技能(`qinsilk-scm` 与 16 个报表技能)逐个登记到 `~/.agents/skills`(多家 AI 助手共同扫描的目录);`--all` 时追加 `~/.claude/skills`、`~/.cursor/skills`。每个技能输出 `linked`(链接,升级自动更新)或 `copied`(降级复制,升级后需重装技能)。
|
|
32
|
+
|
|
33
|
+
## update — 升级
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
scm-agent update
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
从 npm 重新安装最新版(`npm install -g @qinsilk/scm-agent-tools@latest`);技能与命令行一起更新。
|
|
40
|
+
|
|
41
|
+
## docs — 查看说明文档
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
scm-agent docs # 列出包内文档与它们的本机绝对路径
|
|
45
|
+
scm-agent docs api --find cutBedState # 只输出包含该关键词的行
|
|
46
|
+
scm-agent docs api --print # 输出完整文档
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
包内有两份文档:`cli`(本文件,讲命令与参数)与 `api`(接口返回字段字典,讲字段含义、取值枚举、单位、为空的原因)。
|
|
50
|
+
AI 想知道某个字段是什么意思时用 `--find`,不要整份读入上下文。
|
|
51
|
+
|
|
52
|
+
## goods — 商品
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
scm-agent goods search --name A123 # 按款号/名称/条码搜,输出款号、价格、库存、生产中数量等
|
|
56
|
+
scm-agent goods detail --id 12345 # 详情:颜色尺码单品(价格/库存)与工序模板
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## material — 物料
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
scm-agent material search --name 华达呢 # 按名称/货号/条码搜,输出货号、价格、库存、默认供应商
|
|
63
|
+
scm-agent material detail --id 12345 # 详情:单品颜色、规格(属性=值)、价格
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## produce — 生产单
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
scm-agent produce list --sn A123 # 关键词:单号/款号/商品名
|
|
70
|
+
scm-agent produce list --state 2 --from 2026-10-01 --to 2026-10-24 # 按状态与日期区间(至少给一项条件)
|
|
71
|
+
scm-agent produce detail --sn SC202610240001 # 详情:颜色尺码明细 + 工序进度
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
状态值:1草稿 2生产中 3生产完成 4待生产 9已撤销。裁床:详情 JSON 中 `workProcesses` 里 `core=2` 的是裁床工序(`produceNumber` 目标数、`reportNumber` 已汇报数);单据级 `cutBedState`:1不含裁床 2待裁床 3裁床中 4已完成。
|
|
75
|
+
|
|
76
|
+
## material-purchase — 物料采购单
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
scm-agent material-purchase list --sn 供应商名 # 关键词:单号/供应商/生产单号/物料
|
|
80
|
+
scm-agent material-purchase list --from 2026-10-01 --to 2026-10-24
|
|
81
|
+
scm-agent material-purchase detail --sn CG202610240001 # 详情:物料明细(数量/单价/入库)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
状态值:1草稿 2待入库 3部分入库 4全部入库 9撤销;不传状态时默认只查五种进行中的状态(与网页一致)。
|
|
85
|
+
|
|
86
|
+
## design — 设计款与IE核价
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
scm-agent design list --sn A123 # 关键词:款号/名称/条码/货号
|
|
90
|
+
scm-agent design list --state 2 --from 2026-10-01 --to 2026-10-24 # 按状态与日期区间(至少给一项条件)
|
|
91
|
+
scm-agent design ie-list --sn A123 # IE核价:设计款×颜色的物料/工序/费用明细
|
|
92
|
+
scm-agent design ie-list --from 2026-10-01 --to 2026-10-24 # 按开发日期区间,可不带条件全量翻页
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
设计款状态值:2设计中 3待确定 4修改中 5审核通过 6取消 15开发池 16版型资产库。`design list` 的 `--dateType` 决定日期区间作用的时间字段:update更新时间(默认)/ create创建时间 / dev开发时间;`design ie-list` 的 `--dateType` 只有 dev开发时间(默认)/ create创建时间。IE 核价行中 `materials` 物料行、`processFees` 工序费用行、`costFees` 特殊工艺费用行、`accountItems` 其他费用行;无供应商资料权限时供应商字段为空,工序开启隐藏价格时单价为空(与网页可见范围一致)。
|
|
96
|
+
|
|
97
|
+
## design-order — 版单(旗舰版功能)
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
scm-agent design-order list --sn A123 # 关键词:款号/名称/版单号/备注/货号(至少给一项条件)
|
|
101
|
+
scm-agent design-order list --states 1,2 --from 2026-10-01 --to 2026-10-24 # 按状态与下版日期区间
|
|
102
|
+
scm-agent design-order list --node 纸样 # 当前节点为纸样的版单
|
|
103
|
+
scm-agent design-order list --overdue pattern # 纸样逾期的版单(sweep 为车版逾期)
|
|
104
|
+
scm-agent design-order detail --sn FS1024001 # 版单详情(也可 --id <版单id>)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
版单状态值:1未开始 2进行中 3已结束 4废版 9撤销 10审批中 12审批拒绝;审版状态(`--review-state`):2未设置审版 3待审 4已审。列表默认只查未开始/进行中/审批中(与网页一致),要查已结束、废版、撤销的版单需显式传 `--states`;按版单号查详情不受该默认限制。`--dateType` 决定日期区间作用的时间字段:business下版日期(默认)/ create创建 / update更新 / finish预计完成 / delivery交付。详情返回节点进度(`nodes`)、打版数量明细(`dtRows`,颜色×尺码×数量)、BOM 物料行(`bomRows`)、尺码指示(`parts`)、工艺要求(`techniques`)、工序(`workProcesses`)与该设计款全部版单(`serialOrders`)。版单为旗舰版专属功能,未开通的企业返回 482 与提示文案;供应商字段与工序单价按用户权限遮蔽(与网页可见范围一致)。
|
|
108
|
+
|
|
109
|
+
## log — 数据变动日志与接口日志
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
scm-agent log db-change --keywords WL1002 # 按关键词查变动(只匹配变动数据,多个词逗号分隔且都要命中)
|
|
113
|
+
scm-agent log db-change --keywords WL1002 --table scm_material --from 2026-09-01
|
|
114
|
+
scm-agent log db-change --request-id 1790000000000_1060184727 # 查同一请求的全部数据库变动
|
|
115
|
+
scm-agent log api --request-id 1790000000000_1060184727 # 按请求标识查接口日志(标识来自 db-change 返回)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
回答「谁在什么时候通过什么操作改了什么」的两步查询:先用 `log db-change` 按关键词(如物料货号)、表名、操作人 uid 或请求标识查数据库变动日志(时间倒序,至少给一项条件;`--from/--to` 不传默认近 30 天,跨度上限 180 天;`--uid` 可从 `log db-change` 返回行或 user-list 获得)。返回行含操作人(姓名)、操作类型(新增/修改/删除)、变动字段值(`--json` 看完整值)与请求标识;提示「还有更多」时用给出的 `--line-num/--scroll-id` 续查。再取某行的请求标识执行 `log api`,得到这次变动的操作内容(如「修改物料」)、接口路径与参数摘要(超 4000 字符截断)。
|
|
119
|
+
|
|
120
|
+
权限与网页一致:查数据库变动日志需要「日志查询」权限;接口日志任何账号可查,但子账号只能查到自己发起的请求(他人的请求标识返回空是正常行为)。操作时间显示 `-` 的旧记录没有请求标识,查不了接口日志。
|
|
121
|
+
|
|
122
|
+
## report — 生成官方报表
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
scm-agent report <报表名> [参数] [--out 输出目录]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
按官方技能库的格式生成 Excel/HTML 报表文件,输出文件路径与汇总。报表数据全部来自 AI 助手接口(只读)。逐单取详情的报表内置节流(约 2 秒一次请求),单量多时耗时较长属正常。
|
|
129
|
+
|
|
130
|
+
| 报表名 | 生成内容 | 主要参数 |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| `produce-daily` | 生产日报 HTML(今日入库、计划出货、生产状态、风险待料) | `--date`(默认今天) |
|
|
133
|
+
| `produce-board` | 生产节点看板 HTML(近 N 天生产单按工序节点排布) | `--days`(默认 7) |
|
|
134
|
+
| `store-in-goods` | 成品入库报表 Excel(嵌单品图) | `--from --to --sn` |
|
|
135
|
+
| `factory-evaluation` | 工厂评估报表 Excel(单数、裁床数、完成件数、按时交货率) | `--from --to`(默认近一个月) |
|
|
136
|
+
| `produce-cost` | 生产成本报表 Excel(42 列 + 六类成本差异 + 款式图) | `--from --to --state`(默认 4,2,3) |
|
|
137
|
+
| `produce-cost-detail` | 生产成本报表明细(每生产单一个 Excel,含五类成本明细) | `--from --to` |
|
|
138
|
+
| `material-transit` | 物料在途状态报表 Excel(采购在途/已入库未发料/物料缺口三 sheet) | `--days`(默认 90) |
|
|
139
|
+
| `material-purchase-export` | 物料采购导出 Excel(近三个月物料采购子单) | `--from --to` |
|
|
140
|
+
| `supplier-balance` | 供应商对账 Excel(11 表对账单,每供应商一个文件) | `--supplier --from --to` |
|
|
141
|
+
| `leak-check` | 漏料检测日报(每生产单一个「物料数据」Excel) | `--limit`(默认 100)`--include-zero` |
|
|
142
|
+
| `process-followup` | 生产单工序跟进表 Excel(需跟进的工序标红) | `--from --to` |
|
|
143
|
+
| `goods-inventory` | 服装成品盘存表 Excel(动态尺码列) | `--storehouse`(仓库 id) |
|
|
144
|
+
| `ticket-statistics` | 生产状况统计表 Excel(按部门与货号汇总领货交货) | `--from --to`(编菲日期区间,不传则不限) |
|
|
145
|
+
| `goods-bom` | BOM 商品信息(每商品一个 Excel:商品信息+BOM+物料单品) | `--sn --limit` |
|
|
146
|
+
| `goods-size` | 商品尺寸信息(每商品一个 Excel,部位纵向尺码横向) | `--sn --limit --transpose` |
|
|
147
|
+
| `goods-first-order` | 商品首单面料工序单价 Excel(最小公倍数合并单元格) | `--sn --limit` |
|
|
148
|
+
|
|
149
|
+
各报表的详细说明、文件名规则与注意事项见同名技能的 SKILL.md(`skills/<中文名>/SKILL.md`)。
|
|
150
|
+
报表要用的接口字段含义见 [api.md](api.md)。
|
|
151
|
+
|
|
152
|
+
## data — 取报表数据(自定义报表用)
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
scm-agent data # 列出全部数据集与必填条件
|
|
156
|
+
scm-agent data <数据集> [参数] [--page N] [--limit N] [--json]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
官方报表格式固定;用户想按自己公司的口径重新统计时,用 `data` 取原始数据,再由 AI 计算与排表。
|
|
160
|
+
数据集对应官方报表内部使用的那批报表数据接口,权限、限流与报表完全相同(每 Key 每分钟 30 次、每天 600 次)。
|
|
161
|
+
|
|
162
|
+
三条固定规则:
|
|
163
|
+
|
|
164
|
+
1. **必填条件不满足时不发请求**,报错里带一条可复制的示例命令。
|
|
165
|
+
2. **日期跨度上限 92 天**,超过直接报错;要更久就拆成几段。
|
|
166
|
+
3. **分页数据集一次只取一页**,末尾提示还有多少条,用 `--page N` 翻页;不自动翻页。
|
|
167
|
+
|
|
168
|
+
| 数据集 | 必填条件 | 用途 |
|
|
169
|
+
|---|---|---|
|
|
170
|
+
| `company-config` | 无 | 物料小数位、是否启用生产批次号 |
|
|
171
|
+
| `goods-rich` | `--sn` 或 `--search-key` | 商品档案、价格、库存、首单面料、翻单信息;`--on-sale -1` 含停用款 |
|
|
172
|
+
| `goods-bom` | `--id` | 单商品 BOM 全量(物料行、工序单价、尺寸表) |
|
|
173
|
+
| `sku-inventory` | `--storehouse` 或 `--all-storehouses` 二选一 | 单品库存;只含已转大货商品;`--all-storehouses` 是全部仓库合计 |
|
|
174
|
+
| `produce-cost` | `--from --to` | 生产成本(每行含五类成本明细) |
|
|
175
|
+
| `produce-material` | `--from --to` | 物料需求(在途与缺口) |
|
|
176
|
+
| `produce-store-in` | `--from --to` | 生产入库单列表 |
|
|
177
|
+
| `produce-store-in-detail` | `--sn` | 生产入库单详情(明细与委外加工费) |
|
|
178
|
+
| `store-in-statistics` | `--from --to` | 成品入库统计(行级含颜色尺码与金额) |
|
|
179
|
+
| `ticket-statistics` | `--from --to` | 菲票统计(领包人、部门、交货状态) |
|
|
180
|
+
| `factory-evaluation` | `--from --to` | 按加工厂聚合的单数、裁床数、按时交货率 |
|
|
181
|
+
| `supplier-list` | 无 | 供应商名录(对账第一步,取供应商 id) |
|
|
182
|
+
| `supplier-balance` | `--supplier-id --from --to` | 单供应商对账 11 表 |
|
|
183
|
+
| `work-processes` | `--sn` | 生产单工序节点(id 用于查明细) |
|
|
184
|
+
| `work-process-detail` | `--work-process-id` | 单个工序节点的汇报记录 |
|
|
185
|
+
| `material-data` | `--sns`(最多 20 个) | 批量物料占用与使用状态 |
|
|
186
|
+
|
|
187
|
+
两点限制要如实告诉用户:
|
|
188
|
+
|
|
189
|
+
- 关键词参数都是单值模糊匹配,「统计这 5 个款」要分 5 次查询。
|
|
190
|
+
- 跨数据集关联(比如采购单与入库单按单号对上)要分两次取数再本地对齐,算错的风险由 AI 承担;这类需求优先用官方报表。
|
|
191
|
+
|
|
192
|
+
各数据集的字段含义、取值枚举与为空原因见 [api.md](api.md) 的「数据集:」章节。
|
|
193
|
+
|
|
194
|
+
## 自己做报表时怎么查字段
|
|
195
|
+
|
|
196
|
+
官方报表之外,用户希望按自己公司的口径做报表或统计时,先用 `--json` 看返回结构,再用
|
|
197
|
+
`scm-agent docs api --find <字段名>` 确认字段含义、取值枚举、单位与为空的原因。
|
|
198
|
+
`api.md` 覆盖了全部命令与数据集的字段。
|
|
199
|
+
|
|
200
|
+
## 写命令的确认方式(所有写命令通用)
|
|
201
|
+
|
|
202
|
+
写命令(带 `--confirm` 参数的命令)分成两次交互:第一次不带 `--confirm`,只输出预览、不发任何写请求;第二次加 `--confirm` 才提交。中间的「用户是否同意」由**运行 CLI 的 Agent** 用自己的交互界面完成,不是由 CLI 完成——CLI 在 Agent 的子进程里运行,没有交互终端,无法自己弹框。
|
|
203
|
+
|
|
204
|
+
Agent 应调用 `AskUserQuestion`(Codex 里叫 `request_user_input`),给出**「确认」与「取消」两个选项**并附上改动摘要。用户选「确认」才加 `--confirm`;选「取消」不发写请求;想改参数的用户会用对话框自带的「Other」(Codex 是「None of the above」加备注)直接输入文字,此时按该文字重新解析参数、重新预览并再次确认。
|
|
205
|
+
|
|
206
|
+
不存在这类工具的宿主(工具列表里找不到 `AskUserQuestion`)改为文字提问,让用户回复「确认」或「取消」。Codex 的 `request_user_input` 只在 Plan 模式可用,Default 模式下改用文字提问。
|
|
207
|
+
|
|
208
|
+
## user — 员工管理
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
scm-agent user add --name 张三 --login-name abcd --password 1234 [--roles 设计师,版师] [--phone] [--department-id] [--work-sn] [--confirm]
|
|
212
|
+
scm-agent user search --name 张三
|
|
213
|
+
scm-agent user detail --uid 888
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`user add` 创建子账号。**默认只预览**(展示姓名、账号、角色、密码掩码),**加 `--confirm` 才创建**;密码在命令内部做与网页一致的 md5 转换后提交,预览与结果都不显示密码。角色名支持精确或唯一前缀匹配,有歧义时报错列出候选。创建依赖进销存系统联动,失败时错误原样返回。
|
|
217
|
+
|
|
218
|
+
`user search` 按姓名、手机号或工号模糊查询,返回 uid(同名员工会同时列出,按部门区分),用于把「张三」这类姓名换成后续命令需要的 uid。
|
|
219
|
+
|
|
220
|
+
`user detail` 返回员工基本信息与拥有的角色;用户有多个角色时,改权限前必须先让用户选择改哪一个角色的。
|
|
221
|
+
|
|
222
|
+
## role — 角色与权限管理
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
scm-agent role list [--name 设计]
|
|
226
|
+
scm-agent role detail --id 5 | --name 设计师
|
|
227
|
+
scm-agent role add-permission --id 5 | --name 设计师 --permissions 商品管理的查看,goodsEdit [--confirm]
|
|
228
|
+
scm-agent role remove-permission --id 5 | --name 设计师 --permissions 商品管理的查看 [--confirm]
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
`--permissions` 每项可用中文备注(网页权限不足提示引号内的整段文字)、英文权限 key 或菜单 id;解析顺序是「菜单 id → 权限 key → 备注精确 → 唯一包含」,解析失败列出候选。
|
|
232
|
+
|
|
233
|
+
**权限备注会重名**:真实环境 931 项菜单里有 48 个重名备注,最典型的是「商品管理的查看」同时对应按设计师(`goodsGet`)、跟单员(`goodsGetByFollower`)、品牌(`goodsGetByBrand`)、设计助理(`goodsGetByDesignAssistant`)判断四个变体。备注命中多项时命令不猜,报错列出带标题、权限 key、菜单 id 的候选,改用权限 key 或菜单 id 重新提交即可。预览里每条权限也按「备注|标题|权限key|id」完整展示,避免用户确认时分不清是哪一个。
|
|
234
|
+
|
|
235
|
+
权限增减命令**默认只预览**:展示角色、将要增加/移除的权限、现有权限数、改动后权限数与**受影响用户名单**(改角色权限会影响该角色下全部用户);**加 `--confirm` 才执行**。系统内置角色(`role list` 中类型为「系统」)不能修改。服务端的联动权限校验(勾选 A 必须同时勾选 B)报错原样返回。
|
|
236
|
+
|
|
237
|
+
## permission — 权限菜单查询
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
scm-agent permission list [--keyword 查看]
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
权限菜单全量列表:中文备注、功能标题、权限 key、菜单 id 的对照。用于查找权限的确切名称与 id。
|
|
244
|
+
|
|
245
|
+
## 错误码
|
|
246
|
+
|
|
247
|
+
| 码 | 含义 | 处理 |
|
|
248
|
+
|---|---|---|
|
|
249
|
+
| 481 | Key 无效/已过期/已禁用 | 回网页「AI 助手」页面重新生成或启用 |
|
|
250
|
+
| 482 | 权限不足 | 账号权限所致,找管理员 |
|
|
251
|
+
| 483 | Key 已吊销 | 回网页重新生成 |
|
|
252
|
+
| 484 | 请求过于频繁 | 等待一分钟后重试 |
|
package/package.json
CHANGED
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qinsilk/scm-agent-tools",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "秦丝生产ERP AI 助手 CLI:供 AI Agent 查询商品、物料、生产单、物料采购单数据",
|
|
5
|
+
"bin": {
|
|
6
|
+
"scm-agent": "./cli/scm-agent.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"cli/",
|
|
10
|
+
"skills/",
|
|
11
|
+
"reports/",
|
|
12
|
+
"docs/"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "node --test test/cli.test.js"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"exceljs": "^4.4.0",
|
|
22
|
+
"yargs": "^17.7.2"
|
|
23
|
+
},
|
|
24
|
+
"license": "UNLICENSED",
|
|
25
|
+
"private": false,
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/reports/excel.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Excel 生成公共封装:基于 exceljs,提供报表模块共用的表头样式、边框、
|
|
2
|
+
// 红色标注、列宽、嵌图与保存能力。各报表只描述「列与数据」,样式细节统一在这里维护。
|
|
3
|
+
const ExcelJS = require('exceljs');
|
|
4
|
+
|
|
5
|
+
/** 表头行样式:加粗、浅灰底、细边框 */
|
|
6
|
+
const HEADER_FILL = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF2F2F2' } };
|
|
7
|
+
const THIN_BORDER = {
|
|
8
|
+
top: { style: 'thin', color: { argb: 'FFCCCCCC' } },
|
|
9
|
+
left: { style: 'thin', color: { argb: 'FFCCCCCC' } },
|
|
10
|
+
bottom: { style: 'thin', color: { argb: 'FFCCCCCC' } },
|
|
11
|
+
right: { style: 'thin', color: { argb: 'FFCCCCCC' } },
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/** 新建工作簿并设置默认字体(Excel 打开中文正常显示) */
|
|
15
|
+
function createWorkbook() {
|
|
16
|
+
const workbook = new ExcelJS.Workbook();
|
|
17
|
+
workbook.creator = 'scm-agent';
|
|
18
|
+
return workbook;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 写一张标准数据表:
|
|
23
|
+
* - 第一行表头(headers 数组,或对象列定义 { header, width })
|
|
24
|
+
* - 之后每行按 rows 二维数组或对象数组(配合 keys)写入
|
|
25
|
+
* 返回 worksheet,调用方可以继续做合并、嵌图、特殊标色。
|
|
26
|
+
*/
|
|
27
|
+
function addSheet(workbook, name, headers, rows, { keys, headerRowHeight = 22 } = {}) {
|
|
28
|
+
const sheet = workbook.addWorksheet(name, {
|
|
29
|
+
views: [{ state: 'frozen', ySplit: 1 }],
|
|
30
|
+
});
|
|
31
|
+
sheet.addRow(headers.map((h) => (typeof h === 'object' ? h.header : h)));
|
|
32
|
+
const headerRow = sheet.getRow(1);
|
|
33
|
+
headerRow.height = headerRowHeight;
|
|
34
|
+
headerRow.font = { bold: true };
|
|
35
|
+
headerRow.eachCell((cell) => {
|
|
36
|
+
cell.fill = HEADER_FILL;
|
|
37
|
+
cell.border = THIN_BORDER;
|
|
38
|
+
cell.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
|
|
39
|
+
});
|
|
40
|
+
headers.forEach((h, i) => {
|
|
41
|
+
sheet.getColumn(i + 1).width = (typeof h === 'object' ? h.width : undefined) || 14;
|
|
42
|
+
});
|
|
43
|
+
for (const row of rows) {
|
|
44
|
+
const values = keys ? keys.map((k) => (typeof k === 'function' ? k(row) : row[k])) : row;
|
|
45
|
+
const added = sheet.addRow(values);
|
|
46
|
+
added.eachCell((cell) => {
|
|
47
|
+
cell.border = THIN_BORDER;
|
|
48
|
+
cell.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return sheet;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 把某一行整行或部分单元格字体标红(原 Python 报表的「需跟进/差异」红色标注)。
|
|
56
|
+
* rowIndex 从 1 开始(与 exceljs 一致,含表头行)。
|
|
57
|
+
*/
|
|
58
|
+
function markRowRed(sheet, rowIndex, { columns } = {}) {
|
|
59
|
+
const row = sheet.getRow(rowIndex);
|
|
60
|
+
row.eachCell({ includeEmpty: false }, (cell, colNumber) => {
|
|
61
|
+
if (!columns || columns.includes(colNumber)) {
|
|
62
|
+
cell.font = { ...(cell.font || {}), color: { argb: 'FFCC0000' }, bold: true };
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** 单元格字体标色:color 形如 'FFCC0000'(ARGB) */
|
|
68
|
+
function markCellColor(sheet, rowIndex, colIndex, argb, { bold = true } = {}) {
|
|
69
|
+
const cell = sheet.getRow(rowIndex).getCell(colIndex);
|
|
70
|
+
cell.font = { ...(cell.font || {}), color: { argb }, bold };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 在单元格嵌图。image 是 downloadImage 的返回值 { buffer, extension }。
|
|
75
|
+
* ext 作为 exceljs 的 base64 前缀依据。
|
|
76
|
+
*/
|
|
77
|
+
function embedImage(workbook, sheet, image, rowIndex, colIndex, { width = 60, height = 60 } = {}) {
|
|
78
|
+
if (!image) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const imageId = workbook.addImage({
|
|
82
|
+
buffer: image.buffer,
|
|
83
|
+
extension: image.extension === 'jpg' ? 'jpeg' : image.extension,
|
|
84
|
+
});
|
|
85
|
+
sheet.addImage(imageId, {
|
|
86
|
+
tl: { row: rowIndex - 1, col: colIndex - 1 },
|
|
87
|
+
ext: { width, height },
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** 保存文件。目录不存在时自动创建 */
|
|
92
|
+
async function saveWorkbook(workbook, filePath) {
|
|
93
|
+
const fs = require('fs');
|
|
94
|
+
const path = require('path');
|
|
95
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
96
|
+
await workbook.xlsx.writeFile(filePath);
|
|
97
|
+
return filePath;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = {
|
|
101
|
+
createWorkbook,
|
|
102
|
+
addSheet,
|
|
103
|
+
markRowRed,
|
|
104
|
+
markCellColor,
|
|
105
|
+
embedImage,
|
|
106
|
+
saveWorkbook,
|
|
107
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// 工厂评估报表:按加工厂汇总生产明细(单数、下单数、裁床数、完成件数、按时交货率)。
|
|
2
|
+
// 聚合由服务端完成,这里只分页拉取汇总结果并按原脚本的列布局写 Excel。
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { call } = require('../cli/api');
|
|
6
|
+
const { dateStr, shiftDate, timestamp, fetchAll } = require('./util');
|
|
7
|
+
const { createWorkbook, saveWorkbook } = require('./excel');
|
|
8
|
+
|
|
9
|
+
// 汇总说明行文字:解释按时交货率的分母口径,与原脚本一致
|
|
10
|
+
const RULE_TEXT = '汇总规则:按时交货率 = 按时交货单数 / 预计交货日期早于今天的生产单数;预计交货日期为空或未到期不计入分母';
|
|
11
|
+
|
|
12
|
+
// 列定义:(标题, DTO 字段, 类型)。数值列右对齐,百分比列带两位小数百分比格式
|
|
13
|
+
const COLUMNS = [
|
|
14
|
+
{ header: '工厂', field: 'factory', kind: 'text', width: 22 },
|
|
15
|
+
{ header: '单数', field: 'orders', kind: 'number', width: 10 },
|
|
16
|
+
{ header: '下单数', field: 'sumNumber', kind: 'number', width: 12 },
|
|
17
|
+
{ header: '裁床数', field: 'sumCutBedNumber', kind: 'number', width: 12 },
|
|
18
|
+
{ header: '完成件数(生产入库单)', field: 'produceStoreInNumber', kind: 'number', width: 22 },
|
|
19
|
+
{ header: '完成件数(成品入库)', field: 'produceInNumber', kind: 'number', width: 20 },
|
|
20
|
+
{ header: '按时交货率', field: 'onTimeRate', kind: 'percent', width: 12 },
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const BORDER = {
|
|
24
|
+
top: { style: 'thin', color: { argb: 'FF000000' } },
|
|
25
|
+
left: { style: 'thin', color: { argb: 'FF000000' } },
|
|
26
|
+
bottom: { style: 'thin', color: { argb: 'FF000000' } },
|
|
27
|
+
right: { style: 'thin', color: { argb: 'FF000000' } },
|
|
28
|
+
};
|
|
29
|
+
// 表头与标题底色:浅蓝,与原脚本一致
|
|
30
|
+
const HEADER_FILL = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE8F1FB' } };
|
|
31
|
+
|
|
32
|
+
/** 数值列的空值兜底为 0(与原脚本的 number() 一致) */
|
|
33
|
+
function number(value) {
|
|
34
|
+
const parsed = Number(value);
|
|
35
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 生成工厂评估报表 Excel。
|
|
40
|
+
* argv.from/to:业务日期区间 yyyy-MM-dd;默认结束日为今天、起始日往前 30 个日历日
|
|
41
|
+
* (即起始日 = 今天 - 29 天,与原脚本和后端默认口径一致)。
|
|
42
|
+
*/
|
|
43
|
+
async function generate(argv = {}) {
|
|
44
|
+
const to = argv.to || dateStr();
|
|
45
|
+
const from = argv.from || shiftDate(-29, new Date(`${to}T00:00:00`));
|
|
46
|
+
if (from > to) {
|
|
47
|
+
throw new Error('起始日期不能晚于结束日期');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const outDir = argv.out || process.cwd();
|
|
51
|
+
const filePath = path.resolve(outDir, `工厂评估报表${timestamp()}.xlsx`);
|
|
52
|
+
if (fs.existsSync(filePath)) {
|
|
53
|
+
throw new Error(`输出文件已存在:${filePath};如需替换请先删除旧文件或更换输出目录`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 服务端按加工厂聚合并排序(单数降序、工厂名升序),这里分页取全量汇总行
|
|
57
|
+
const { list: summary } = await fetchAll(
|
|
58
|
+
(page, limit) => call('GET', '/api/agent/v1/report/factory-evaluation', { from, to, page, limit })
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const workbook = createWorkbook();
|
|
62
|
+
const sheet = workbook.addWorksheet('工厂评估报表', {
|
|
63
|
+
views: [{ state: 'frozen', ySplit: 3 }],
|
|
64
|
+
pageSetup: { orientation: 'landscape', fitToPage: true, fitToWidth: 1, fitToHeight: 0 },
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// 第 1 行:表标题,整行合并
|
|
68
|
+
const titleRow = sheet.addRow(['工厂评估报表']);
|
|
69
|
+
titleRow.height = 26;
|
|
70
|
+
titleRow.getCell(1).font = { bold: true };
|
|
71
|
+
titleRow.getCell(1).fill = HEADER_FILL;
|
|
72
|
+
titleRow.getCell(1).alignment = { vertical: 'middle', horizontal: 'center' };
|
|
73
|
+
|
|
74
|
+
// 第 2 行:汇总规则说明,左对齐整行合并
|
|
75
|
+
const ruleRow = sheet.addRow([RULE_TEXT]);
|
|
76
|
+
ruleRow.height = 20;
|
|
77
|
+
ruleRow.getCell(1).alignment = { vertical: 'middle', horizontal: 'left', wrapText: true };
|
|
78
|
+
|
|
79
|
+
// 第 3 行:表头
|
|
80
|
+
const headerRow = sheet.addRow(COLUMNS.map((column) => column.header));
|
|
81
|
+
headerRow.height = 30;
|
|
82
|
+
headerRow.eachCell((cell) => {
|
|
83
|
+
cell.font = { bold: true };
|
|
84
|
+
cell.fill = HEADER_FILL;
|
|
85
|
+
cell.border = BORDER;
|
|
86
|
+
cell.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// 数据行:按时交货率为空(无已到期生产单)时写文本「-」,不能写成 0
|
|
90
|
+
for (const item of summary) {
|
|
91
|
+
const values = COLUMNS.map((column) => {
|
|
92
|
+
if (column.kind === 'percent') {
|
|
93
|
+
return item.onTimeRate == null ? '-' : number(item.onTimeRate) / 100;
|
|
94
|
+
}
|
|
95
|
+
return column.kind === 'text' ? item[column.field] : number(item[column.field]);
|
|
96
|
+
});
|
|
97
|
+
const row = sheet.addRow(values);
|
|
98
|
+
row.height = 20;
|
|
99
|
+
row.eachCell((cell, colNumber) => {
|
|
100
|
+
const kind = COLUMNS[colNumber - 1].kind;
|
|
101
|
+
cell.border = BORDER;
|
|
102
|
+
cell.alignment = {
|
|
103
|
+
vertical: 'middle',
|
|
104
|
+
horizontal: kind === 'text' ? 'left' : 'right',
|
|
105
|
+
wrapText: kind === 'text',
|
|
106
|
+
};
|
|
107
|
+
if (kind === 'percent' && cell.value !== '-') {
|
|
108
|
+
cell.numFmt = '0.00%';
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
COLUMNS.forEach((column, i) => {
|
|
114
|
+
sheet.getColumn(i + 1).width = column.width;
|
|
115
|
+
});
|
|
116
|
+
sheet.mergeCells(1, 1, 1, COLUMNS.length);
|
|
117
|
+
sheet.mergeCells(2, 1, 2, COLUMNS.length);
|
|
118
|
+
|
|
119
|
+
await saveWorkbook(workbook, filePath);
|
|
120
|
+
|
|
121
|
+
const orderTotal = summary.reduce((sum, item) => sum + number(item.orders), 0);
|
|
122
|
+
return {
|
|
123
|
+
filePaths: [filePath],
|
|
124
|
+
summary: `工厂评估报表已生成:业务日期 ${from} ~ ${to},生产单 ${orderTotal} 张汇总为 ${summary.length} 个加工厂`,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
module.exports = { generate };
|