wjx-cli 0.1.5 → 0.1.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.
package/README.md CHANGED
@@ -1,841 +1,856 @@
1
- # wjx-cli
2
-
3
- > 问卷星 (Wenjuanxing) CLI — AI Agent 原生命令行工具
4
-
5
- [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
6
- [![node](https://img.shields.io/badge/node-%3E%3D20-green)](https://nodejs.org/)
7
- [![npm](https://img.shields.io/npm/v/wjx-cli)](https://www.npmjs.com/package/wjx-cli)
8
- [![tests](https://img.shields.io/badge/tests-80%20passing-brightgreen)](__tests__/cli.test.mjs)
9
-
10
- wjx-cli 是 [`wjx-ai-kit`](../) monorepo 的命令行入口,将 [wjx-api-sdk](../wjx-api-sdk/) 的 50+ 函数直接暴露为终端命令。设计目标:**让 AI Agent 和人类开发者都能用一行命令操作问卷星 OpenAPI**。
11
-
12
- ---
13
-
14
- ## 目录
15
-
16
- - [特性](#特性)
17
- - [**快速开始**](#快速开始)
18
- - [安装](#安装)
19
- - [认证](#认证)
20
- - [架构](#架构)
21
- - [全局选项](#全局选项)
22
- - [命令参考](#命令参考)
23
- - [survey — 问卷管理](#survey--问卷管理)
24
- - [response — 答卷管理](#response--答卷管理)
25
- - [contacts — 通讯录](#contacts--通讯录)
26
- - [department — 部门管理](#department--部门管理)
27
- - [admin — 管理员](#admin--管理员)
28
- - [tag — 标签管理](#tag--标签管理)
29
- - [user-system — 用户体系](#user-system--用户体系)
30
- - [account — 子账号管理](#account--子账号管理)
31
- - [sso — 单点登录](#sso--单点登录)
32
- - [analytics — 数据分析](#analytics--数据分析)
33
- - [诊断工具](#诊断工具)
34
- - [stdin 管道输入](#stdin-管道输入)
35
- - [输出格式](#输出格式)
36
- - [错误协议](#错误协议)
37
- - [Agent 集成指南](#agent-集成指南)
38
- - [环境变量](#环境变量)
39
- - [开发](#开发)
40
- - [常见问题](#常见问题)
41
- - [相关项目](#相关项目)
42
- - [许可证](#许可证)
43
-
44
- ---
45
-
46
- ## 特性
47
-
48
- - **AI Agent 原生** — 默认 JSON stdout + 结构化 JSON stderr,退出码区分错误类型,适合程序解析
49
- - **stdin pipe** — `echo '{"vid":123}' | wjx --stdin survey get`,参数通过管道传入
50
- - **表格输出** — `--table` 切换为人类可读的 `console.table` 格式
51
- - **56 个子命令** — 覆盖问卷、答卷、通讯录、部门、管理员、标签、用户体系、子账号、SSO、数据分析
52
- - **9 个本地命令** — SSO URL 生成和 analytics 计算无需 API Key,离线可用
53
- - **基于 wjx-api-sdk** — 直接调用 SDK 函数,类型安全,行为与 API 一致
54
-
55
- ---
56
-
57
- ## 快速开始
58
-
59
- ```bash
60
- npm install -g wjx-cli
61
- export WJX_API_KEY=你的ApiKey
62
- wjx survey list
63
- ```
64
-
65
- > **新手?** 阅读 [快速开始教程](docs/getting-started.md),含 [Node.js 安装指引](docs/install-nodejs.md)。
66
-
67
- ---
68
-
69
- ## 前置条件
70
-
71
- - **Node.js >= 20**([安装指引](docs/install-nodejs.md))
72
- - **问卷星 OpenAPI API Key**([申请方式](https://www.wjx.cn/openapi/))
73
-
74
- ---
75
-
76
- ## 安装
77
-
78
- ```bash
79
- npm install -g wjx-cli
80
- ```
81
-
82
- ### 从源码安装(开发者)
83
-
84
- ```bash
85
- git clone <your-repo-url>
86
- cd wjx-ai-kit
87
- npm install
88
- npm run build --workspace=wjx-api-sdk
89
- npm run build --workspace=wjx-cli
90
- npm link --workspace=wjx-cli
91
- ```
92
-
93
- ---
94
-
95
- ## 认证
96
-
97
- 大多数命令需要问卷星 API Key(SSO 和 analytics 命令除外)。
98
-
99
- ```bash
100
- # 方式 1:环境变量(推荐)
101
- export WJX_API_KEY=your_api_key
102
-
103
- # 方式 2:命令行参数
104
- wjx --api-key your_api_key survey list
105
-
106
- # 方式 3:.env 文件(SDK 自动读取)
107
- echo "WJX_API_KEY=your_api_key" >> .env
108
- ```
109
-
110
- ---
111
-
112
- ## 架构
113
-
114
- ```
115
- wjx-ai-kit/ # monorepo root
116
- ├── wjx-api-sdk/ # TypeScript SDK(50+ 函数,零依赖)
117
- ├── wjx-mcp-server/ # MCP Server(56 tools,供 Claude/Cursor 使用)
118
- └── wjx-cli/ # ← 本项目
119
- ├── src/
120
- │ ├── index.ts # Commander 入口 + 全局 preAction hook
121
- │ ├── commands/ # 11 个命令模块(每模块 1 个 register 函数)
122
- │ │ ├── survey.ts # 14 subcommands
123
- │ │ ├── response.ts # 11 subcommands
124
- │ │ ├── contacts.ts # 3 subcommands
125
- │ │ ├── department.ts # 4 subcommands
126
- │ │ ├── admin.ts # 3 subcommands
127
- ├── tag.ts # 4 subcommands
128
- ├── user-system.ts # 6 subcommands
129
- │ │ ├── account.ts # 5 subcommands
130
- │ │ ├── sso.ts # 3 subcommands(无需 API Key)
131
- │ │ ├── analytics.ts # 6 subcommands(本地计算,无需 API Key)
132
- │ │ └── diagnostics.ts # 2 subcommands(whoami + doctor)
133
- └── lib/
134
- ├── command-helpers.ts # executeCommand + strictInt + requireField
135
- ├── auth.ts # API Key 获取(env > --api-key)
136
- ├── output.ts # JSON / table 格式化
137
- ├── errors.ts # CliError + exit code 路由
138
- └── stdin.ts # stdin JSON 读取 + source-aware merge
139
- └── __tests__/
140
- └── cli.test.mjs # 80 个端到端测试
141
- ```
142
-
143
- **数据流:** `CLI args / stdin` → `Commander parse` → `executeCommand()` `wjx-api-sdk function` → `stdout JSON / stderr error`
144
-
145
- ---
146
-
147
- ## 全局选项
148
-
149
- | 选项 | 说明 |
150
- |------|------|
151
- | `--api-key <apiKey>` | WJX API Key(或设置 `WJX_API_KEY` 环境变量) |
152
- | `--json` | JSON 输出(默认) |
153
- | `--table` | 表格输出(`console.table` 格式) |
154
- | `--verbose` | 详细输出 |
155
- | `--stdin` | 从 stdin 读取 JSON 参数(见 [stdin 管道输入](#stdin-管道输入)) |
156
- | `--version` | 显示版本号 |
157
- | `--help` | 显示帮助信息 |
158
-
159
- ---
160
-
161
- ## 命令参考
162
-
163
- ### survey 问卷管理
164
-
165
- 14 个子命令,覆盖问卷的完整生命周期。
166
-
167
- ```bash
168
- wjx survey list # 列出问卷
169
- wjx survey get --vid 12345 # 获取详情
170
- wjx survey create --title "新问卷" # 创建问卷
171
- wjx survey status --vid 12345 --state 1 # 发布(1=发布, 2=暂停, 3=删除)
172
- wjx survey export-text --vid 12345 # 导出为纯文本
173
- wjx survey url --mode create # 生成创建/编辑 URL
174
- ```
175
-
176
- <details>
177
- <summary>全部选项参考</summary>
178
-
179
- | 子命令 | 选项 | 必填 | 类型 | 说明 |
180
- |--------|------|:----:|------|------|
181
- | **list** | `--page` | | int | 页码 |
182
- | | `--page_size` | | int | 每页数量 |
183
- | | `--status` | | int | 状态筛选 |
184
- | | `--atype` | | int | 问卷类型 |
185
- | | `--name_like` | | string | 名称模糊搜索 |
186
- | **get** | `--vid` | **是** | int | 问卷 ID |
187
- | **create** | `--title` | **是** | string | 问卷标题 |
188
- | | `--type` | | int | 问卷类型(默认 0) |
189
- | | `--description` | | string | 问卷描述 |
190
- | | `--questions` | | json | 题目 JSON 数组 |
191
- | | `--source_vid` | | string | 复制源问卷 ID |
192
- | | `--publish` | | flag | 创建后立即发布 |
193
- | **delete** | `--vid` | **是** | int | 问卷 ID |
194
- | | `--username` | **是** | string | 用户名 |
195
- | | `--completely` | | flag | 彻底删除(不进回收站) |
196
- | **status** | `--vid` | **是** | int | 问卷 ID |
197
- | | `--state` | **是** | int | 目标状态(1=发布, 2=暂停, 3=删除) |
198
- | **settings** | `--vid` | **是** | int | 问卷 ID |
199
- | **update-settings** | `--vid` | **是** | int | 问卷 ID |
200
- | | `--api_setting` | | json | API 设置 |
201
- | | `--after_submit_setting` | | json | 提交后设置 |
202
- | | `--msg_setting` | | json | 消息设置 |
203
- | | `--sojumpparm_setting` | | json | 参数设置 |
204
- | | `--time_setting` | | json | 时间设置 |
205
- | **tags** | `--username` | **是** | string | 用户名 |
206
- | **tag-details** | `--tag_id` | **是** | int | 标签 ID |
207
- | **clear-bin** | `--username` | **是** | string | 用户名 |
208
- | | `--vid` | | int | 指定问卷 ID(不填则清空全部) |
209
- | **upload** | `--file_name` | **是** | string | 文件名 |
210
- | | `--file` | **是** | string | 文件 Base64 内容 |
211
- | **export-text** | `--vid` | **是** | int | 问卷 ID |
212
- | | `--raw` | | flag | 输出纯文本(不包裹 JSON) |
213
- | **url** | `--mode` | | string | `create` 或 `edit`(默认 create) |
214
- | | `--name` | | string | 问卷名称(create 模式) |
215
- | | `--activity` | | int | 问卷 vid(edit 模式必填) |
216
-
217
- </details>
218
-
219
- ### response 答卷管理
220
-
221
- 11 个子命令,管理答卷数据的查询、提交、下载和统计。
222
-
223
- ```bash
224
- wjx response count --vid 12345 # 获取答卷总数
225
- wjx response query --vid 12345 # 查询答卷
226
- wjx response realtime --vid 12345 # 实时最新答卷
227
- wjx response download --vid 12345 # 下载答卷
228
- wjx response submit --vid 12345 --inputcosttime 60 --submitdata "1$2"
229
- wjx response report --vid 12345 # 统计报告
230
- ```
231
-
232
- <details>
233
- <summary>全部选项参考</summary>
234
-
235
- | 子命令 | 选项 | 必填 | 类型 | 说明 |
236
- |--------|------|:----:|------|------|
237
- | **count** | `--vid` | **是** | int | 问卷 ID |
238
- | **query** | `--vid` | **是** | int | 问卷 ID |
239
- | | `--page_index` | | int | 页码 |
240
- | | `--page_size` | | int | 每页数量 |
241
- | | `--sort` | | int | 排序 |
242
- | | `--min_index` | | int | 最小序号 |
243
- | | `--jid` | | string | 答卷 ID |
244
- | | `--sojumpparm` | | string | 自定义参数 |
245
- | | `--qid` | | string | 题目 ID |
246
- | | `--begin_time` | | int | 开始时间 |
247
- | | `--end_time` | | int | 结束时间 |
248
- | | `--file_view_expires` | | int | 文件链接有效期 |
249
- | | `--query_note` | | flag | 查询备注 |
250
- | | `--distinct_user` | | flag | 去重用户 |
251
- | | `--distinct_sojumpparm` | | flag | 去重参数 |
252
- | | `--conds` | | string | 查询条件 |
253
- | **realtime** | `--vid` | **是** | int | 问卷 ID |
254
- | | `--count` | | int | 返回数量 |
255
- | **download** | `--vid` | **是** | int | 问卷 ID |
256
- | | `--taskid` | | string | 任务 ID |
257
- | | `--query_count` | | int | 查询数量 |
258
- | | `--begin_time` | | int | 开始时间 |
259
- | | `--end_time` | | int | 结束时间 |
260
- | | `--min_index` | | int | 最小序号 |
261
- | | `--qid` | | string | 题目 ID |
262
- | | `--sort` | | int | 排序 |
263
- | | `--query_type` | | int | 查询类型 |
264
- | | `--suffix` | | int | 文件后缀 |
265
- | | `--query_record` | | flag | 查询记录 |
266
- | **submit** | `--vid` | **是** | int | 问卷 ID |
267
- | | `--inputcosttime` | **是** | int | 填写耗时(秒) |
268
- | | `--submitdata` | **是** | string | 提交数据 |
269
- | | `--udsid` | | int | 用户系统 ID |
270
- | | `--sojumpparm` | | string | 自定义参数 |
271
- | | `--submittime` | | string | 提交时间 |
272
- | **modify** | `--vid` | **是** | int | 问卷 ID |
273
- | | `--jid` | **是** | int | 答卷 ID |
274
- | | `--answers` | **是** | string | 答案数据 |
275
- | **clear** | `--username` | **是** | string | 用户名 |
276
- | | `--vid` | **是** | int | 问卷 ID |
277
- | | `--reset_to_zero` | | flag | 重置序号 |
278
- | **report** | `--vid` | **是** | int | 问卷 ID |
279
- | | `--min_index` | | int | 最小序号 |
280
- | | `--jid` | | string | 答卷 ID |
281
- | | `--sojumpparm` | | string | 自定义参数 |
282
- | | `--begin_time` | | int | 开始时间 |
283
- | | `--end_time` | | int | 结束时间 |
284
- | | `--distinct_user` | | flag | 去重用户 |
285
- | | `--distinct_sojumpparm` | | flag | 去重参数 |
286
- | | `--conds` | | string | 查询条件 |
287
- | **files** | `--vid` | **是** | int | 问卷 ID |
288
- | | `--file_keys` | **是** | string | 文件 Key 列表 |
289
- | | `--file_view_expires` | | int | 链接有效期 |
290
- | **winners** | `--vid` | **是** | int | 问卷 ID |
291
- | | `--atype` | | int | 活动类型 |
292
- | | `--awardstatus` | | int | 领奖状态 |
293
- | | `--page_index` | | int | 页码 |
294
- | | `--page_size` | | int | 每页数量 |
295
- | **360-report** | `--vid` | **是** | int | 问卷 ID |
296
- | | `--taskid` | | string | 任务 ID |
297
-
298
- </details>
299
-
300
- ### contacts 通讯录
301
-
302
- ```bash
303
- wjx contacts query --uid user1 # 查询联系人
304
- wjx contacts add --users '[{"name":"张三"}]' # 添加联系人
305
- wjx contacts delete --uids "uid1,uid2" # 删除联系人
306
- ```
307
-
308
- | 子命令 | 选项 | 必填 | 类型 | 说明 |
309
- |--------|------|:----:|------|------|
310
- | **query** | `--uid` | **是** | string | 用户 ID |
311
- | | `--corpid` | | string | 企业 ID |
312
- | **add** | `--users` | **是** | json | 用户 JSON 数组 |
313
- | | `--corpid` | | string | 企业 ID |
314
- | | `--auto_create_udept` | | flag | 自动创建部门 |
315
- | | `--auto_create_tag` | | flag | 自动创建标签 |
316
- | **delete** | `--uids` | **是** | string | 用户 ID 列表(逗号分隔) |
317
- | | `--corpid` | | string | 企业 ID |
318
-
319
- ### department 部门管理
320
-
321
- ```bash
322
- wjx department list # 列出部门
323
- wjx department add --depts '[{"name":"研发"}]'
324
- wjx department modify --depts '[{"id":1,"name":"技术"}]'
325
- wjx department delete --depts '[{"id":1}]' --type 1
326
- ```
327
-
328
- | 子命令 | 选项 | 必填 | 类型 | 说明 |
329
- |--------|------|:----:|------|------|
330
- | **list** | `--corpid` | | string | 企业 ID |
331
- | **add** | `--depts` | **是** | json | 部门路径 JSON 数组 |
332
- | | `--corpid` | | string | 企业 ID |
333
- | **modify** | `--depts` | **是** | json | 部门对象 JSON 数组 |
334
- | | `--corpid` | | string | 企业 ID |
335
- | **delete** | `--type` | **是** | string | 类型(1=按ID, 2=按名称) |
336
- | | `--depts` | **是** | json | 部门标识 JSON 数组 |
337
- | | `--corpid` | | string | 企业 ID |
338
- | | `--del_child` | | flag | 同时删除子部门 |
339
-
340
- ### admin 管理员
341
-
342
- ```bash
343
- wjx admin add --users '[{"uid":"u1","role":1}]'
344
- wjx admin delete --uids "uid1,uid2"
345
- wjx admin restore --uids "uid1"
346
- ```
347
-
348
- | 子命令 | 选项 | 必填 | 类型 | 说明 |
349
- |--------|------|:----:|------|------|
350
- | **add** | `--users` | **是** | json | 管理员 JSON 数组 |
351
- | | `--corpid` | | string | 企业 ID |
352
- | **delete** | `--uids` | **是** | string | 用户 ID 列表(逗号分隔) |
353
- | | `--corpid` | | string | 企业 ID |
354
- | **restore** | `--uids` | **是** | string | 用户 ID 列表(逗号分隔) |
355
- | | `--corpid` | | string | 企业 ID |
356
-
357
- ### tag 标签管理
358
-
359
- ```bash
360
- wjx tag list # 列出标签
361
- wjx tag add --child_names '["VIP","普通"]'
362
- wjx tag modify --tp_id 1 --child_names '["新VIP"]'
363
- wjx tag delete --tags '[{"id":1}]' --type 1
364
- ```
365
-
366
- | 子命令 | 选项 | 必填 | 类型 | 说明 |
367
- |--------|------|:----:|------|------|
368
- | **list** | `--corpid` | | string | 企业 ID |
369
- | **add** | `--child_names` | **是** | json | 标签路径 JSON 数组 |
370
- | | `--corpid` | | string | 企业 ID |
371
- | | `--is_radio` | | flag | 单选标签 |
372
- | **modify** | `--tp_id` | **是** | string | 标签组 ID |
373
- | | `--tp_name` | | string | 标签组名称 |
374
- | | `--child_names` | | json | 标签对象 JSON 数组 |
375
- | | `--corpid` | | string | 企业 ID |
376
- | **delete** | `--type` | **是** | string | 类型(1=按ID, 2=按名称) |
377
- | | `--tags` | **是** | json | 标签标识 JSON 数组 |
378
- | | `--corpid` | | string | 企业 ID |
379
-
380
- ### user-system 用户体系
381
-
382
- 6 个子命令,管理用户系统中的参与者和问卷绑定。
383
-
384
- ```bash
385
- wjx user-system add-participants --username u1 --sysid 1 --users '[...]'
386
- wjx user-system bind --username u1 --sysid 1 --uids "a" --vid 12345
387
- wjx user-system query-binding --username u1 --sysid 1 --vid 12345
388
- wjx user-system query-surveys --username u1 --sysid 1 --uid "a"
389
- ```
390
-
391
- <details>
392
- <summary>全部选项参考</summary>
393
-
394
- | 子命令 | 选项 | 必填 | 类型 | 说明 |
395
- |--------|------|:----:|------|------|
396
- | **add-participants** | `--username` | **是** | string | 用户名 |
397
- | | `--users` | **是** | json | 参与者 JSON |
398
- | | `--sysid` | **是** | int | 系统 ID |
399
- | **modify-participants** | `--username` | **是** | string | 用户名 |
400
- | | `--users` | **是** | json | 参与者 JSON |
401
- | | `--sysid` | **是** | int | 系统 ID |
402
- | **delete-participants** | `--username` | **是** | string | 用户名 |
403
- | | `--uids` | **是** | json | 用户 ID JSON 数组 |
404
- | | `--sysid` | **是** | int | 系统 ID |
405
- | **bind** | `--username` | **是** | string | 用户名 |
406
- | | `--vid` | **是** | int | 问卷 ID |
407
- | | `--sysid` | **是** | int | 系统 ID |
408
- | | `--uids` | **是** | string | 参与者 ID 列表 |
409
- | | `--answer_times` | | int | 可答次数 |
410
- | | `--can_chg_answer` | | flag | 允许修改答案 |
411
- | | `--can_view_result` | | flag | 允许查看结果 |
412
- | | `--can_hide_qlist` | | int | 隐藏问卷列表 |
413
- | **query-binding** | `--username` | **是** | string | 用户名 |
414
- | | `--vid` | **是** | int | 问卷 ID |
415
- | | `--sysid` | **是** | int | 系统 ID |
416
- | | `--page_index` | | int | 页码 |
417
- | | `--page_size` | | int | 每页数量 |
418
- | | `--join_status` | | int | 参与状态 |
419
- | | `--day` | | string | 按天筛选 |
420
- | | `--week` | | string | 按周筛选 |
421
- | | `--month` | | string | 按月筛选 |
422
- | | `--force_join_times` | | flag | 强制参与次数 |
423
- | **query-surveys** | `--username` | **是** | string | 用户名 |
424
- | | `--uid` | **是** | string | 参与者 ID |
425
- | | `--sysid` | **是** | int | 系统 ID |
426
- | | `--page_index` | | int | 页码 |
427
- | | `--page_size` | | int | 每页数量 |
428
-
429
- </details>
430
-
431
- ### account 子账号管理
432
-
433
- ```bash
434
- wjx account list # 查询子账号
435
- wjx account add --subuser test1 --password pass123
436
- wjx account modify --subuser test1 --email new@test.com
437
- wjx account delete --subuser test1
438
- wjx account restore --subuser test1
439
- ```
440
-
441
- <details>
442
- <summary>全部选项参考</summary>
443
-
444
- | 子命令 | 选项 | 必填 | 类型 | 说明 |
445
- |--------|------|:----:|------|------|
446
- | **list** | `--subuser` | | string | 子账号用户名 |
447
- | | `--name_like` | | string | 名称模糊搜索 |
448
- | | `--role` | | int | 角色 |
449
- | | `--group` | | int | 分组 |
450
- | | `--page_index` | | int | 页码 |
451
- | | `--page_size` | | int | 每页数量 |
452
- | | `--mobile` | | string | 手机号 |
453
- | **add** | `--subuser` | **是** | string | 子账号用户名 |
454
- | | `--password` | | string | 密码 |
455
- | | `--mobile` | | string | 手机号 |
456
- | | `--email` | | string | 邮箱 |
457
- | | `--role` | | int | 角色 |
458
- | | `--group` | | int | 分组 |
459
- | **modify** | `--subuser` | **是** | string | 子账号用户名 |
460
- | | `--mobile` | | string | 手机号 |
461
- | | `--email` | | string | 邮箱 |
462
- | | `--role` | | int | 角色 |
463
- | | `--group` | | int | 分组 |
464
- | **delete** | `--subuser` | **是** | string | 子账号用户名 |
465
- | **restore** | `--subuser` | **是** | string | 子账号用户名 |
466
- | | `--mobile` | | string | 手机号 |
467
- | | `--email` | | string | 邮箱 |
468
-
469
- </details>
470
-
471
- ### sso 单点登录
472
-
473
- > **无需 API Key** SSO 命令在本地生成 URL,不调用 API。
474
-
475
- ```bash
476
- wjx sso subaccount-url --subuser test1 # 子账号 SSO 链接
477
- wjx sso user-system-url --u admin --system_id 1 --uid user1
478
- wjx sso partner-url --username partner1 # 代理商 SSO 链接
479
- ```
480
-
481
- <details>
482
- <summary>全部选项参考</summary>
483
-
484
- | 子命令 | 选项 | 必填 | 类型 | 说明 |
485
- |--------|------|:----:|------|------|
486
- | **subaccount-url** | `--subuser` | **是** | string | 子账号用户名 |
487
- | | `--mobile` | | string | 手机号 |
488
- | | `--email` | | string | 邮箱 |
489
- | | `--role_id` | | int | 角色 ID |
490
- | | `--url` | | string | 登录后跳转 URL |
491
- | | `--admin` | | int | 主账号登录(1) |
492
- | **user-system-url** | `--u` | **是** | string | 账号用户名 |
493
- | | `--system_id` | **是** | int | 用户系统 ID |
494
- | | `--uid` | **是** | string | 参与者 ID |
495
- | | `--uname` | | string | 参与者名称 |
496
- | | `--udept` | | string | 参与者部门 |
497
- | | `--uextf` | | string | 扩展字段 |
498
- | | `--upass` | | string | 密码 |
499
- | | `--is_login` | | int | 是否登录(0/1) |
500
- | | `--activity` | | int | 跳转问卷 vid |
501
- | | `--return_url` | | string | 返回 URL |
502
- | **partner-url** | `--username` | **是** | string | 代理商用户名 |
503
- | | `--mobile` | | string | 手机号 |
504
- | | `--subuser` | | string | 子账号用户名 |
505
-
506
- </details>
507
-
508
- ### analytics 数据分析
509
-
510
- > **无需 API Key** analytics 命令在本地执行计算,不调用 API。
511
-
512
- ```bash
513
- wjx analytics decode --submitdata "1$2}2$hello" # 解码答卷提交数据
514
- wjx analytics nps --scores "[9,10,7,3,8,10,9]" # 计算 NPS 分数
515
- wjx analytics csat --scores "[4,5,3,5,2]" # 计算 CSAT 分数
516
- wjx analytics csat --scores "[5,6,4]" --scale 7-point
517
- wjx analytics anomalies --responses '[...]' # 异常答卷检测
518
- wjx analytics compare --set_a '{"score":80}' --set_b '{"score":90}'
519
- wjx analytics decode-push --payload "..." --app_key "key"
520
- ```
521
-
522
- | 子命令 | 选项 | 必填 | 类型 | 说明 |
523
- |--------|------|:----:|------|------|
524
- | **decode** | `--submitdata` | **是** | string | 提交数据字符串 |
525
- | **nps** | `--scores` | **是** | json | 评分 JSON 数组(0-10) |
526
- | **csat** | `--scores` | **是** | json | 评分 JSON 数组 |
527
- | | `--scale` | | string | 量表类型:`5-point` 或 `7-point`(默认 5-point) |
528
- | **anomalies** | `--responses` | **是** | json | 答卷数据 JSON 数组 |
529
- | **compare** | `--set_a` | **是** | json | 指标集 A JSON 对象 |
530
- | | `--set_b` | **是** | json | 指标集 B JSON 对象 |
531
- | **decode-push** | `--payload` | **是** | string | 加密推送数据 |
532
- | | `--app_key` | **是** | string | AppKey |
533
- | | `--signature` | | string | 签名 |
534
- | | `--raw_body` | | string | 原始请求体 |
535
-
536
- ### 诊断工具
537
-
538
- ```bash
539
- wjx whoami # 验证 API Key 并显示账号信息(调用 listSurveys 检测)
540
- wjx doctor # 环境诊断(Node 版本、API Key、API 连接、SDK 版本)
541
- ```
542
-
543
- ---
544
-
545
- ## stdin 管道输入
546
-
547
- 通过 `--stdin` 标志从管道读取 JSON 参数。CLI 显式指定的选项优先于 stdin 中的同名字段(source-aware merge)。
548
-
549
- ```bash
550
- # 基本用法
551
- echo '{"vid": 12345}' | wjx --stdin survey get
552
-
553
- # 多字段
554
- echo '{"page": 1, "page_size": 20}' | wjx --stdin survey list
555
-
556
- # CLI 参数覆盖 stdin(source-aware:只有 CLI 显式指定的值才会覆盖)
557
- echo '{"vid": 12345, "state": 1}' | wjx --stdin survey status --state 2
558
- # → state=2(CLI 显式指定),vid=12345(来自 stdin)
559
-
560
- # 配合 jq 链式调用
561
- wjx survey list | jq '.data[0].vid' | xargs -I{} wjx survey get --vid {}
562
-
563
- # Agent 工作流:先查问卷,再导出文本
564
- VID=$(wjx survey list | jq -r '.data.activitys | to_entries[0].value.vid')
565
- wjx survey export-text --vid "$VID" --raw
566
- ```
567
-
568
- **规则:**
569
- - stdin 必须是 JSON 对象(不能是数组或原始值)
570
- - stdin 不报错,等同于不使用 `--stdin`
571
- - 非法 JSON `INPUT_ERROR` exit 2
572
-
573
- ---
574
-
575
- ## 输出格式
576
-
577
- ### JSON(默认)
578
-
579
- 成功时输出到 stdout:
580
-
581
- ```bash
582
- $ wjx survey url --mode create
583
- {
584
- "url": "https://www.wjx.cn/..."
585
- }
586
- ```
587
-
588
- ### 表格
589
-
590
- ```bash
591
- $ wjx --table survey list
592
- ┌─────────┬───────┬──────────────┬────────┐
593
- │ (index) │ vid │ title │ status │
594
- ├─────────┼───────┼──────────────┼────────┤
595
- │ 0 │ 12345 │ '客户满意度' │ 1 │
596
- └─────────┴───────┴──────────────┴────────┘
597
- ```
598
-
599
- ### 错误
600
-
601
- 错误输出到 **stderr**(stdout 为空),详见下方 [错误协议](#错误协议)。
602
-
603
- ---
604
-
605
- ## 错误协议
606
-
607
- wjx-cli 使用结构化 JSON 错误输出,方便 AI Agent 和自动化脚本解析。
608
-
609
- ### stderr JSON Schema
610
-
611
- ```json
612
- {
613
- "error": true,
614
- "message": "错误描述(人类可读)",
615
- "code": "API_ERROR | AUTH_ERROR | INPUT_ERROR",
616
- "exitCode": 1
617
- }
618
- ```
619
-
620
- | 字段 | 类型 | 说明 |
621
- |------|------|------|
622
- | `error` | `boolean` | 恒为 `true` |
623
- | `message` | `string` | 错误描述 |
624
- | `code` | `string` | 错误分类(见下表) |
625
- | `exitCode` | `number` | 进程退出码 |
626
-
627
- ### 退出码
628
-
629
- | 退出码 | 错误码 | 含义 | 典型场景 |
630
- |:------:|--------|------|----------|
631
- | **0** | — | 成功 | 命令正常完成 |
632
- | **1** | `API_ERROR` | API 错误 | 网络错误、API 返回失败 |
633
- | **1** | `AUTH_ERROR` | 认证错误 | API Key 缺失或无效 |
634
- | **2** | `INPUT_ERROR` | 输入错误 | 缺少必填参数、无效整数、JSON 解析失败 |
635
-
636
- ### 示例
637
-
638
- ```bash
639
- # 缺少 API Key exit 1, AUTH_ERROR
640
- $ wjx survey list 2>&1 >/dev/null
641
- {"error":true,"message":"WJX_API_KEY 未设置。请通过 --api-key 参数或 WJX_API_KEY 环境变量提供。","code":"AUTH_ERROR","exitCode":1}
642
-
643
- # 缺少必填参数 exit 2, INPUT_ERROR
644
- $ wjx survey get 2>&1 >/dev/null
645
- {"error":true,"message":"Missing required option: --vid","code":"INPUT_ERROR","exitCode":2}
646
-
647
- # 无效整数 → exit 2, INPUT_ERROR
648
- $ wjx survey get --vid abc 2>&1 >/dev/null
649
- {"error":true,"message":"Invalid integer: \"abc\"","code":"INPUT_ERROR","exitCode":2}
650
- ```
651
-
652
- ### Agent 错误处理模式
653
-
654
- ```python
655
- import subprocess, json
656
-
657
- result = subprocess.run(["wjx", "survey", "get", "--vid", "12345"],
658
- capture_output=True, text=True)
659
-
660
- if result.returncode == 0:
661
- data = json.loads(result.stdout)
662
- elif result.returncode == 2:
663
- # 输入错误 — 修正参数后重试
664
- err = json.loads(result.stderr)
665
- print(f"Bad input: {err['message']}")
666
- elif result.returncode == 1:
667
- # API/认证错误 检查 API Key 或稍后重试
668
- err = json.loads(result.stderr)
669
- print(f"API error: {err['message']}")
670
- ```
671
-
672
- ---
673
-
674
- ## Agent 集成指南
675
-
676
- wjx-cli 的设计目标是成为 AI Agent 的问卷星 API 操作工具。以下是典型集成模式。
677
-
678
- ### 作为 LLM Tool 使用
679
-
680
- ```json
681
- {
682
- "type": "function",
683
- "function": {
684
- "name": "wjx_survey_list",
685
- "description": "列出问卷星中的所有问卷",
686
- "parameters": {
687
- "type": "object",
688
- "properties": {
689
- "page": { "type": "integer", "description": "页码" },
690
- "page_size": { "type": "integer", "description": "每页数量" }
691
- }
692
- }
693
- }
694
- }
695
- ```
696
-
697
- Agent 实现:
698
-
699
- ```python
700
- def execute_wjx_tool(name, args):
701
- cmd = ["wjx"] + name.replace("wjx_", "").replace("_", " ").split()
702
- for k, v in args.items():
703
- cmd.extend([f"--{k}", str(v)])
704
- result = subprocess.run(cmd, capture_output=True, text=True)
705
- return json.loads(result.stdout) if result.returncode == 0 \
706
- else json.loads(result.stderr)
707
- ```
708
-
709
- ### stdin pipe 批量操作
710
-
711
- ```bash
712
- # 批量查询多个问卷的答卷数
713
- for vid in 12345 12346 12347; do
714
- echo "{\"vid\": $vid}" | wjx --stdin response count
715
- done
716
-
717
- # 结合 jq 构造复杂参数
718
- echo '{"title":"调查","type":0,"questions":"[]"}' | wjx --stdin survey create
719
- ```
720
-
721
- ### 与 wjx-mcp-server 的关系
722
-
723
- | 场景 | 推荐工具 |
724
- |------|----------|
725
- | Claude Desktop / Cursor 等 MCP 客户端 | `wjx-mcp-server` |
726
- | 终端 / shell 脚本 / CI/CD | `wjx-cli` |
727
- | 自定义 Agent(Python/Node/Go) | `wjx-cli`(子进程)或 `wjx-api-sdk`(直接导入) |
728
- | 需要 56 MCP tools + resources + prompts | `wjx-mcp-server` |
729
- | 需要简单的 JSON in / JSON out | `wjx-cli` |
730
-
731
- ---
732
-
733
- ## 环境变量
734
-
735
- | 变量 | 必填 | 说明 | 默认值 |
736
- |------|:----:|------|--------|
737
- | `WJX_API_KEY` | 是* | 问卷星 OpenAPI API Key | — |
738
- | `WJX_CORP_ID` | | 企业通讯录 ID(通讯录相关操作需要) | |
739
- | `WJX_BASE_URL` | | 自定义 API 基础域名 | `https://www.wjx.cn` |
740
-
741
- \* SSO 和 analytics 命令不需要 API Key。
742
-
743
- ---
744
-
745
- ## 开发
746
-
747
- ```bash
748
- cd wjx-ai-kit/wjx-cli
749
-
750
- npm run build # TypeScript 编译 → dist/
751
- npm test # 构建 + 运行 80 个测试
752
- npm run clean # 清理 dist/
753
-
754
- # 手动测试
755
- node dist/index.js --help
756
- node dist/index.js survey url --mode create
757
- WJX_API_KEY=xxx node dist/index.js survey list
758
- ```
759
-
760
- ### 项目结构
761
-
762
- ```
763
- src/
764
- ├── index.ts # 入口 + Commander program
765
- ├── commands/ # 11 个命令模块
766
- │ └── *.ts # 每个文件导出 register*Commands(program)
767
- └── lib/
768
- ├── command-helpers.ts # executeCommand / strictInt / requireField
769
- ├── auth.ts # API Key 获取
770
- ├── output.ts # JSON / table 输出
771
- ├── errors.ts # CliError + 退出码路由
772
- └── stdin.ts # stdin 读取 + source-aware merge
773
- ```
774
-
775
- ### 添加新命令
776
-
777
- 1. `wjx-api-sdk` 中确认 SDK 函数已导出
778
- 2. 创建 `src/commands/<module>.ts`,导出 `register<Module>Commands(program)`
779
- 3. 在 `src/index.ts` 中注册
780
- 4. `__tests__/cli.test.mjs` 中添加测试
781
- 5. `npm test` 验证
782
-
783
- ---
784
-
785
- ## 常见问题
786
-
787
- ### `AUTH_ERROR: WJX_API_KEY 未设置`
788
-
789
- 确保设置了 API Key:
790
-
791
- ```bash
792
- export WJX_API_KEY=your_api_key
793
- #
794
- wjx --api-key your_api_key survey list
795
- ```
796
-
797
- ### `INPUT_ERROR: Invalid integer: "abc"`
798
-
799
- 整数参数必须是纯数字,不接受 `123abc` 或 `12.5` 等值。
800
-
801
- ### `INPUT_ERROR: stdin JSON must be an object`
802
-
803
- `--stdin` 只接受 JSON 对象,不接受数组或原始值:
804
-
805
- ```bash
806
- # 错误
807
- echo '[1,2,3]' | wjx --stdin survey list
808
-
809
- # 正确
810
- echo '{"page":1}' | wjx --stdin survey list
811
- ```
812
-
813
- ### API 连接问题
814
-
815
- 运行诊断:
816
-
817
- ```bash
818
- wjx doctor
819
- ```
820
-
821
- 如需指向测试环境:
822
-
823
- ```bash
824
- export WJX_BASE_URL=https://your-test-server.com
825
- ```
826
-
827
- ---
828
-
829
- ## 相关项目
830
-
831
- | 项目 | 说明 |
832
- |------|------|
833
- | [wjx-ai-kit](../) | Monorepo 根目录 |
834
- | [wjx-api-sdk](../wjx-api-sdk/) | TypeScript SDK(50+ 函数,零依赖) |
835
- | [wjx-mcp-server](../wjx-mcp-server/) | MCP Server(56 tools,供 Claude/Cursor 使用) |
836
-
837
- ---
838
-
839
- ## 许可证
840
-
841
- [MIT](LICENSE)
1
+ # wjx-cli
2
+
3
+ > 问卷星 (Wenjuanxing) CLI — AI Agent 原生命令行工具
4
+
5
+ [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
6
+ [![node](https://img.shields.io/badge/node-%3E%3D20-green)](https://nodejs.org/)
7
+ [![npm](https://img.shields.io/npm/v/wjx-cli)](https://www.npmjs.com/package/wjx-cli)
8
+ [![tests](https://img.shields.io/badge/tests-82%20passing-brightgreen)](__tests__/cli.test.mjs)
9
+
10
+ wjx-cli 是 [`wjx-ai-kit`](../) monorepo 的命令行入口,将 [wjx-api-sdk](../wjx-api-sdk/) 的 50+ 函数直接暴露为终端命令。设计目标:**让 AI Agent 和人类开发者都能用一行命令操作问卷星 OpenAPI**。
11
+
12
+ ---
13
+
14
+ ## 目录
15
+
16
+ - [特性](#特性)
17
+ - [**快速开始**](#快速开始)
18
+ - [安装](#安装)
19
+ - [认证](#认证)
20
+ - [架构](#架构)
21
+ - [全局选项](#全局选项)
22
+ - [命令参考](#命令参考)
23
+ - [survey — 问卷管理](#survey--问卷管理)
24
+ - [response — 答卷管理](#response--答卷管理)
25
+ - [contacts — 通讯录](#contacts--通讯录)
26
+ - [department — 部门管理](#department--部门管理)
27
+ - [admin — 管理员](#admin--管理员)
28
+ - [tag — 标签管理](#tag--标签管理)
29
+ - [user-system — 用户体系](#user-system--用户体系)
30
+ - [account — 子账号管理](#account--子账号管理)
31
+ - [sso — 单点登录](#sso--单点登录)
32
+ - [analytics — 数据分析](#analytics--数据分析)
33
+ - [配置与诊断](#配置与诊断)
34
+ - [stdin 管道输入](#stdin-管道输入)
35
+ - [输出格式](#输出格式)
36
+ - [错误协议](#错误协议)
37
+ - [Agent 集成指南](#agent-集成指南)
38
+ - [环境变量](#环境变量)
39
+ - [开发](#开发)
40
+ - [常见问题](#常见问题)
41
+ - [相关项目](#相关项目)
42
+ - [许可证](#许可证)
43
+
44
+ ---
45
+
46
+ ## 特性
47
+
48
+ - **AI Agent 原生** — 默认 JSON stdout + 结构化 JSON stderr,退出码区分错误类型,适合程序解析
49
+ - **stdin pipe** — `echo '{"vid":123}' | wjx --stdin survey get`,参数通过管道传入
50
+ - **表格输出** — `--table` 切换为人类可读的 `console.table` 格式
51
+ - **56 个子命令** — 覆盖问卷、答卷、通讯录、部门、管理员、标签、用户体系、子账号、SSO、数据分析
52
+ - **9 个本地命令** — SSO URL 生成和 analytics 计算无需 API Key,离线可用
53
+ - **基于 wjx-api-sdk** — 直接调用 SDK 函数,类型安全,行为与 API 一致
54
+
55
+ ---
56
+
57
+ ## 快速开始
58
+
59
+ ```bash
60
+ npm install -g wjx-cli
61
+ wjx init # 交互式配置 API Key、Base URL、Corp ID
62
+ wjx doctor # 环境诊断
63
+ wjx survey list # 查看问卷列表
64
+ ```
65
+
66
+ > **新手?** 阅读 [快速开始教程](docs/getting-started.md),含 [Node.js 安装指引](docs/install-nodejs.md)。
67
+
68
+ ---
69
+
70
+ ## 前置条件
71
+
72
+ - **Node.js >= 20**([安装指引](docs/install-nodejs.md))
73
+ - **问卷星 OpenAPI API Key**([申请方式](https://www.wjx.cn/openapi/))
74
+
75
+ ---
76
+
77
+ ## 安装
78
+
79
+ ```bash
80
+ npm install -g wjx-cli
81
+ ```
82
+
83
+ ### 从源码安装(开发者)
84
+
85
+ ```bash
86
+ git clone <your-repo-url>
87
+ cd wjx-ai-kit
88
+ npm install
89
+ npm run build --workspace=wjx-api-sdk
90
+ npm run build --workspace=wjx-cli
91
+ npm link --workspace=wjx-cli
92
+ ```
93
+
94
+ ---
95
+
96
+ ## 认证
97
+
98
+ 大多数命令需要问卷星 API Key(SSO 和 analytics 命令除外)。
99
+
100
+ 凭据解析优先级:`--api-key` 参数 > 环境变量 > `~/.wjxrc` 配置文件。
101
+
102
+ ```bash
103
+ # 方式 1:交互式配置(推荐,首次使用)
104
+ wjx init
105
+
106
+ # 方式 2:环境变量
107
+ export WJX_API_KEY=your_api_key
108
+
109
+ # 方式 3:命令行参数
110
+ wjx --api-key your_api_key survey list
111
+
112
+ # 方式 4:直接编辑配置文件
113
+ cat ~/.wjxrc
114
+ # {"apiKey":"your_api_key","baseUrl":"https://www.wjx.cn","corpId":"orgXXX"}
115
+ ```
116
+
117
+ ---
118
+
119
+ ## 架构
120
+
121
+ ```
122
+ wjx-ai-kit/ # monorepo root
123
+ ├── wjx-api-sdk/ # TypeScript SDK(50+ 函数,零依赖)
124
+ ├── wjx-mcp-server/ # MCP Server(56 tools,供 Claude/Cursor 使用)
125
+ └── wjx-cli/ # 本项目
126
+ ├── src/
127
+ │ ├── index.ts # Commander 入口 + 全局 preAction hook
128
+ │ ├── commands/ # 12 个命令模块(每模块 1 个 register 函数)
129
+ │ │ ├── init.ts # wjx init 交互式配置向导
130
+ │ │ ├── survey.ts # 14 subcommands
131
+ │ │ ├── response.ts # 11 subcommands
132
+ │ │ ├── contacts.ts # 3 subcommands
133
+ │ ├── department.ts # 4 subcommands
134
+ ├── admin.ts # 3 subcommands
135
+ ├── tag.ts # 4 subcommands
136
+ ├── user-system.ts # 6 subcommands
137
+ ├── account.ts # 5 subcommands
138
+ │ ├── sso.ts # 3 subcommands(无需 API Key)
139
+ │ │ ├── analytics.ts # 6 subcommands(本地计算,无需 API Key)
140
+ │ │ └── diagnostics.ts # 2 subcommands(whoami + doctor)
141
+ │ └── lib/
142
+ │ ├── config.ts # ~/.wjxrc 配置文件读写 + applyConfigToEnv
143
+ │ ├── command-helpers.ts # executeCommand + strictInt + requireField
144
+ │ ├── auth.ts # API Key 获取(--api-key > env > config)
145
+ │ ├── output.ts # JSON / table 格式化
146
+ │ ├── errors.ts # CliError + exit code 路由
147
+ │ └── stdin.ts # stdin JSON 读取 + source-aware merge
148
+ └── __tests__/
149
+ └── cli.test.mjs # 82 个端到端测试
150
+ ```
151
+
152
+ **数据流:** `CLI args / stdin` → `Commander parse` → `executeCommand()` → `wjx-api-sdk function` → `stdout JSON / stderr error`
153
+
154
+ ---
155
+
156
+ ## 全局选项
157
+
158
+ | 选项 | 说明 |
159
+ |------|------|
160
+ | `--api-key <apiKey>` | WJX API Key(或设置 `WJX_API_KEY` 环境变量) |
161
+ | `--json` | JSON 输出(默认) |
162
+ | `--table` | 表格输出(`console.table` 格式) |
163
+ | `--verbose` | 详细输出 |
164
+ | `--stdin` | 从 stdin 读取 JSON 参数(见 [stdin 管道输入](#stdin-管道输入)) |
165
+ | `--version` | 显示版本号 |
166
+ | `--help` | 显示帮助信息 |
167
+
168
+ ---
169
+
170
+ ## 命令参考
171
+
172
+ ### survey 问卷管理
173
+
174
+ 14 个子命令,覆盖问卷的完整生命周期。
175
+
176
+ ```bash
177
+ wjx survey list # 列出问卷
178
+ wjx survey get --vid 12345 # 获取详情
179
+ wjx survey create --title "新问卷" # 创建问卷
180
+ wjx survey status --vid 12345 --state 1 # 发布(1=发布, 2=暂停, 3=删除)
181
+ wjx survey export-text --vid 12345 # 导出为纯文本
182
+ wjx survey url --mode create # 生成创建/编辑 URL
183
+ ```
184
+
185
+ <details>
186
+ <summary>全部选项参考</summary>
187
+
188
+ | 子命令 | 选项 | 必填 | 类型 | 说明 |
189
+ |--------|------|:----:|------|------|
190
+ | **list** | `--page` | | int | 页码 |
191
+ | | `--page_size` | | int | 每页数量 |
192
+ | | `--status` | | int | 状态筛选 |
193
+ | | `--atype` | | int | 问卷类型 |
194
+ | | `--name_like` | | string | 名称模糊搜索 |
195
+ | **get** | `--vid` | **是** | int | 问卷 ID |
196
+ | **create** | `--title` | **是** | string | 问卷标题 |
197
+ | | `--type` | | int | 问卷类型(默认 0) |
198
+ | | `--description` | | string | 问卷描述 |
199
+ | | `--questions` | | json | 题目 JSON 数组 |
200
+ | | `--source_vid` | | string | 复制源问卷 ID |
201
+ | | `--publish` | | flag | 创建后立即发布 |
202
+ | **delete** | `--vid` | **是** | int | 问卷 ID |
203
+ | | `--username` | **是** | string | 用户名 |
204
+ | | `--completely` | | flag | 彻底删除(不进回收站) |
205
+ | **status** | `--vid` | **是** | int | 问卷 ID |
206
+ | | `--state` | **是** | int | 目标状态(1=发布, 2=暂停, 3=删除) |
207
+ | **settings** | `--vid` | **是** | int | 问卷 ID |
208
+ | **update-settings** | `--vid` | **是** | int | 问卷 ID |
209
+ | | `--api_setting` | | json | API 设置 |
210
+ | | `--after_submit_setting` | | json | 提交后设置 |
211
+ | | `--msg_setting` | | json | 消息设置 |
212
+ | | `--sojumpparm_setting` | | json | 参数设置 |
213
+ | | `--time_setting` | | json | 时间设置 |
214
+ | **tags** | `--username` | **是** | string | 用户名 |
215
+ | **tag-details** | `--tag_id` | **是** | int | 标签 ID |
216
+ | **clear-bin** | `--username` | **是** | string | 用户名 |
217
+ | | `--vid` | | int | 指定问卷 ID(不填则清空全部) |
218
+ | **upload** | `--file_name` | **是** | string | 文件名 |
219
+ | | `--file` | **是** | string | 文件 Base64 内容 |
220
+ | **export-text** | `--vid` | **是** | int | 问卷 ID |
221
+ | | `--raw` | | flag | 输出纯文本(不包裹 JSON) |
222
+ | **url** | `--mode` | | string | `create` 或 `edit`(默认 create) |
223
+ | | `--name` | | string | 问卷名称(create 模式) |
224
+ | | `--activity` | | int | 问卷 vid(edit 模式必填) |
225
+
226
+ </details>
227
+
228
+ ### response 答卷管理
229
+
230
+ 11 个子命令,管理答卷数据的查询、提交、下载和统计。
231
+
232
+ ```bash
233
+ wjx response count --vid 12345 # 获取答卷总数
234
+ wjx response query --vid 12345 # 查询答卷
235
+ wjx response realtime --vid 12345 # 实时最新答卷
236
+ wjx response download --vid 12345 # 下载答卷
237
+ wjx response submit --vid 12345 --inputcosttime 60 --submitdata "1$2"
238
+ wjx response report --vid 12345 # 统计报告
239
+ ```
240
+
241
+ <details>
242
+ <summary>全部选项参考</summary>
243
+
244
+ | 子命令 | 选项 | 必填 | 类型 | 说明 |
245
+ |--------|------|:----:|------|------|
246
+ | **count** | `--vid` | **是** | int | 问卷 ID |
247
+ | **query** | `--vid` | **是** | int | 问卷 ID |
248
+ | | `--page_index` | | int | 页码 |
249
+ | | `--page_size` | | int | 每页数量 |
250
+ | | `--sort` | | int | 排序 |
251
+ | | `--min_index` | | int | 最小序号 |
252
+ | | `--jid` | | string | 答卷 ID |
253
+ | | `--sojumpparm` | | string | 自定义参数 |
254
+ | | `--qid` | | string | 题目 ID |
255
+ | | `--begin_time` | | int | 开始时间 |
256
+ | | `--end_time` | | int | 结束时间 |
257
+ | | `--file_view_expires` | | int | 文件链接有效期 |
258
+ | | `--query_note` | | flag | 查询备注 |
259
+ | | `--distinct_user` | | flag | 去重用户 |
260
+ | | `--distinct_sojumpparm` | | flag | 去重参数 |
261
+ | | `--conds` | | string | 查询条件 |
262
+ | **realtime** | `--vid` | **是** | int | 问卷 ID |
263
+ | | `--count` | | int | 返回数量 |
264
+ | **download** | `--vid` | **是** | int | 问卷 ID |
265
+ | | `--taskid` | | string | 任务 ID |
266
+ | | `--query_count` | | int | 查询数量 |
267
+ | | `--begin_time` | | int | 开始时间 |
268
+ | | `--end_time` | | int | 结束时间 |
269
+ | | `--min_index` | | int | 最小序号 |
270
+ | | `--qid` | | string | 题目 ID |
271
+ | | `--sort` | | int | 排序 |
272
+ | | `--query_type` | | int | 查询类型 |
273
+ | | `--suffix` | | int | 文件后缀 |
274
+ | | `--query_record` | | flag | 查询记录 |
275
+ | **submit** | `--vid` | **是** | int | 问卷 ID |
276
+ | | `--inputcosttime` | **是** | int | 填写耗时(秒) |
277
+ | | `--submitdata` | **是** | string | 提交数据 |
278
+ | | `--udsid` | | int | 用户系统 ID |
279
+ | | `--sojumpparm` | | string | 自定义参数 |
280
+ | | `--submittime` | | string | 提交时间 |
281
+ | **modify** | `--vid` | **是** | int | 问卷 ID |
282
+ | | `--jid` | **是** | int | 答卷 ID |
283
+ | | `--answers` | **是** | string | 答案数据 |
284
+ | **clear** | `--username` | **是** | string | 用户名 |
285
+ | | `--vid` | **是** | int | 问卷 ID |
286
+ | | `--reset_to_zero` | | flag | 重置序号 |
287
+ | **report** | `--vid` | **是** | int | 问卷 ID |
288
+ | | `--min_index` | | int | 最小序号 |
289
+ | | `--jid` | | string | 答卷 ID |
290
+ | | `--sojumpparm` | | string | 自定义参数 |
291
+ | | `--begin_time` | | int | 开始时间 |
292
+ | | `--end_time` | | int | 结束时间 |
293
+ | | `--distinct_user` | | flag | 去重用户 |
294
+ | | `--distinct_sojumpparm` | | flag | 去重参数 |
295
+ | | `--conds` | | string | 查询条件 |
296
+ | **files** | `--vid` | **是** | int | 问卷 ID |
297
+ | | `--file_keys` | **是** | string | 文件 Key 列表 |
298
+ | | `--file_view_expires` | | int | 链接有效期 |
299
+ | **winners** | `--vid` | **是** | int | 问卷 ID |
300
+ | | `--atype` | | int | 活动类型 |
301
+ | | `--awardstatus` | | int | 领奖状态 |
302
+ | | `--page_index` | | int | 页码 |
303
+ | | `--page_size` | | int | 每页数量 |
304
+ | **360-report** | `--vid` | **是** | int | 问卷 ID |
305
+ | | `--taskid` | | string | 任务 ID |
306
+
307
+ </details>
308
+
309
+ ### contacts — 通讯录
310
+
311
+ ```bash
312
+ wjx contacts query --uid user1 # 查询联系人
313
+ wjx contacts add --users '[{"name":"张三"}]' # 添加联系人
314
+ wjx contacts delete --uids "uid1,uid2" # 删除联系人
315
+ ```
316
+
317
+ | 子命令 | 选项 | 必填 | 类型 | 说明 |
318
+ |--------|------|:----:|------|------|
319
+ | **query** | `--uid` | **是** | string | 用户 ID |
320
+ | | `--corpid` | | string | 企业 ID |
321
+ | **add** | `--users` | **是** | json | 用户 JSON 数组 |
322
+ | | `--corpid` | | string | 企业 ID |
323
+ | | `--auto_create_udept` | | flag | 自动创建部门 |
324
+ | | `--auto_create_tag` | | flag | 自动创建标签 |
325
+ | **delete** | `--uids` | **是** | string | 用户 ID 列表(逗号分隔) |
326
+ | | `--corpid` | | string | 企业 ID |
327
+
328
+ ### department 部门管理
329
+
330
+ ```bash
331
+ wjx department list # 列出部门
332
+ wjx department add --depts '[{"name":"研发"}]'
333
+ wjx department modify --depts '[{"id":1,"name":"技术"}]'
334
+ wjx department delete --depts '[{"id":1}]' --type 1
335
+ ```
336
+
337
+ | 子命令 | 选项 | 必填 | 类型 | 说明 |
338
+ |--------|------|:----:|------|------|
339
+ | **list** | `--corpid` | | string | 企业 ID |
340
+ | **add** | `--depts` | **是** | json | 部门路径 JSON 数组 |
341
+ | | `--corpid` | | string | 企业 ID |
342
+ | **modify** | `--depts` | **是** | json | 部门对象 JSON 数组 |
343
+ | | `--corpid` | | string | 企业 ID |
344
+ | **delete** | `--type` | **是** | string | 类型(1=按ID, 2=按名称) |
345
+ | | `--depts` | **是** | json | 部门标识 JSON 数组 |
346
+ | | `--corpid` | | string | 企业 ID |
347
+ | | `--del_child` | | flag | 同时删除子部门 |
348
+
349
+ ### admin — 管理员
350
+
351
+ ```bash
352
+ wjx admin add --users '[{"uid":"u1","role":1}]'
353
+ wjx admin delete --uids "uid1,uid2"
354
+ wjx admin restore --uids "uid1"
355
+ ```
356
+
357
+ | 子命令 | 选项 | 必填 | 类型 | 说明 |
358
+ |--------|------|:----:|------|------|
359
+ | **add** | `--users` | **是** | json | 管理员 JSON 数组 |
360
+ | | `--corpid` | | string | 企业 ID |
361
+ | **delete** | `--uids` | **是** | string | 用户 ID 列表(逗号分隔) |
362
+ | | `--corpid` | | string | 企业 ID |
363
+ | **restore** | `--uids` | **是** | string | 用户 ID 列表(逗号分隔) |
364
+ | | `--corpid` | | string | 企业 ID |
365
+
366
+ ### tag 标签管理
367
+
368
+ ```bash
369
+ wjx tag list # 列出标签
370
+ wjx tag add --child_names '["VIP","普通"]'
371
+ wjx tag modify --tp_id 1 --child_names '["新VIP"]'
372
+ wjx tag delete --tags '[{"id":1}]' --type 1
373
+ ```
374
+
375
+ | 子命令 | 选项 | 必填 | 类型 | 说明 |
376
+ |--------|------|:----:|------|------|
377
+ | **list** | `--corpid` | | string | 企业 ID |
378
+ | **add** | `--child_names` | **是** | json | 标签路径 JSON 数组 |
379
+ | | `--corpid` | | string | 企业 ID |
380
+ | | `--is_radio` | | flag | 单选标签 |
381
+ | **modify** | `--tp_id` | **是** | string | 标签组 ID |
382
+ | | `--tp_name` | | string | 标签组名称 |
383
+ | | `--child_names` | | json | 标签对象 JSON 数组 |
384
+ | | `--corpid` | | string | 企业 ID |
385
+ | **delete** | `--type` | **是** | string | 类型(1=按ID, 2=按名称) |
386
+ | | `--tags` | **是** | json | 标签标识 JSON 数组 |
387
+ | | `--corpid` | | string | 企业 ID |
388
+
389
+ ### user-system — 用户体系
390
+
391
+ 6 个子命令,管理用户系统中的参与者和问卷绑定。
392
+
393
+ ```bash
394
+ wjx user-system add-participants --username u1 --sysid 1 --users '[...]'
395
+ wjx user-system bind --username u1 --sysid 1 --uids "a" --vid 12345
396
+ wjx user-system query-binding --username u1 --sysid 1 --vid 12345
397
+ wjx user-system query-surveys --username u1 --sysid 1 --uid "a"
398
+ ```
399
+
400
+ <details>
401
+ <summary>全部选项参考</summary>
402
+
403
+ | 子命令 | 选项 | 必填 | 类型 | 说明 |
404
+ |--------|------|:----:|------|------|
405
+ | **add-participants** | `--username` | **是** | string | 用户名 |
406
+ | | `--users` | **是** | json | 参与者 JSON |
407
+ | | `--sysid` | **是** | int | 系统 ID |
408
+ | **modify-participants** | `--username` | **是** | string | 用户名 |
409
+ | | `--users` | **是** | json | 参与者 JSON |
410
+ | | `--sysid` | **是** | int | 系统 ID |
411
+ | **delete-participants** | `--username` | **是** | string | 用户名 |
412
+ | | `--uids` | **是** | json | 用户 ID JSON 数组 |
413
+ | | `--sysid` | **是** | int | 系统 ID |
414
+ | **bind** | `--username` | **是** | string | 用户名 |
415
+ | | `--vid` | **是** | int | 问卷 ID |
416
+ | | `--sysid` | **是** | int | 系统 ID |
417
+ | | `--uids` | **是** | string | 参与者 ID 列表 |
418
+ | | `--answer_times` | | int | 可答次数 |
419
+ | | `--can_chg_answer` | | flag | 允许修改答案 |
420
+ | | `--can_view_result` | | flag | 允许查看结果 |
421
+ | | `--can_hide_qlist` | | int | 隐藏问卷列表 |
422
+ | **query-binding** | `--username` | **是** | string | 用户名 |
423
+ | | `--vid` | **是** | int | 问卷 ID |
424
+ | | `--sysid` | **是** | int | 系统 ID |
425
+ | | `--page_index` | | int | 页码 |
426
+ | | `--page_size` | | int | 每页数量 |
427
+ | | `--join_status` | | int | 参与状态 |
428
+ | | `--day` | | string | 按天筛选 |
429
+ | | `--week` | | string | 按周筛选 |
430
+ | | `--month` | | string | 按月筛选 |
431
+ | | `--force_join_times` | | flag | 强制参与次数 |
432
+ | **query-surveys** | `--username` | **是** | string | 用户名 |
433
+ | | `--uid` | **是** | string | 参与者 ID |
434
+ | | `--sysid` | **是** | int | 系统 ID |
435
+ | | `--page_index` | | int | 页码 |
436
+ | | `--page_size` | | int | 每页数量 |
437
+
438
+ </details>
439
+
440
+ ### account — 子账号管理
441
+
442
+ ```bash
443
+ wjx account list # 查询子账号
444
+ wjx account add --subuser test1 --password pass123
445
+ wjx account modify --subuser test1 --email new@test.com
446
+ wjx account delete --subuser test1
447
+ wjx account restore --subuser test1
448
+ ```
449
+
450
+ <details>
451
+ <summary>全部选项参考</summary>
452
+
453
+ | 子命令 | 选项 | 必填 | 类型 | 说明 |
454
+ |--------|------|:----:|------|------|
455
+ | **list** | `--subuser` | | string | 子账号用户名 |
456
+ | | `--name_like` | | string | 名称模糊搜索 |
457
+ | | `--role` | | int | 角色 |
458
+ | | `--group` | | int | 分组 |
459
+ | | `--page_index` | | int | 页码 |
460
+ | | `--page_size` | | int | 每页数量 |
461
+ | | `--mobile` | | string | 手机号 |
462
+ | **add** | `--subuser` | **是** | string | 子账号用户名 |
463
+ | | `--password` | | string | 密码 |
464
+ | | `--mobile` | | string | 手机号 |
465
+ | | `--email` | | string | 邮箱 |
466
+ | | `--role` | | int | 角色 |
467
+ | | `--group` | | int | 分组 |
468
+ | **modify** | `--subuser` | **是** | string | 子账号用户名 |
469
+ | | `--mobile` | | string | 手机号 |
470
+ | | `--email` | | string | 邮箱 |
471
+ | | `--role` | | int | 角色 |
472
+ | | `--group` | | int | 分组 |
473
+ | **delete** | `--subuser` | **是** | string | 子账号用户名 |
474
+ | **restore** | `--subuser` | **是** | string | 子账号用户名 |
475
+ | | `--mobile` | | string | 手机号 |
476
+ | | `--email` | | string | 邮箱 |
477
+
478
+ </details>
479
+
480
+ ### sso — 单点登录
481
+
482
+ > **无需 API Key** — SSO 命令在本地生成 URL,不调用 API。
483
+
484
+ ```bash
485
+ wjx sso subaccount-url --subuser test1 # 子账号 SSO 链接
486
+ wjx sso user-system-url --u admin --system_id 1 --uid user1
487
+ wjx sso partner-url --username partner1 # 代理商 SSO 链接
488
+ ```
489
+
490
+ <details>
491
+ <summary>全部选项参考</summary>
492
+
493
+ | 子命令 | 选项 | 必填 | 类型 | 说明 |
494
+ |--------|------|:----:|------|------|
495
+ | **subaccount-url** | `--subuser` | **是** | string | 子账号用户名 |
496
+ | | `--mobile` | | string | 手机号 |
497
+ | | `--email` | | string | 邮箱 |
498
+ | | `--role_id` | | int | 角色 ID |
499
+ | | `--url` | | string | 登录后跳转 URL |
500
+ | | `--admin` | | int | 主账号登录(1) |
501
+ | **user-system-url** | `--u` | **是** | string | 账号用户名 |
502
+ | | `--system_id` | **是** | int | 用户系统 ID |
503
+ | | `--uid` | **是** | string | 参与者 ID |
504
+ | | `--uname` | | string | 参与者名称 |
505
+ | | `--udept` | | string | 参与者部门 |
506
+ | | `--uextf` | | string | 扩展字段 |
507
+ | | `--upass` | | string | 密码 |
508
+ | | `--is_login` | | int | 是否登录(0/1) |
509
+ | | `--activity` | | int | 跳转问卷 vid |
510
+ | | `--return_url` | | string | 返回 URL |
511
+ | **partner-url** | `--username` | **是** | string | 代理商用户名 |
512
+ | | `--mobile` | | string | 手机号 |
513
+ | | `--subuser` | | string | 子账号用户名 |
514
+
515
+ </details>
516
+
517
+ ### analytics 数据分析
518
+
519
+ > **无需 API Key** analytics 命令在本地执行计算,不调用 API。
520
+
521
+ ```bash
522
+ wjx analytics decode --submitdata "1$2}2$hello" # 解码答卷提交数据
523
+ wjx analytics nps --scores "[9,10,7,3,8,10,9]" # 计算 NPS 分数
524
+ wjx analytics csat --scores "[4,5,3,5,2]" # 计算 CSAT 分数
525
+ wjx analytics csat --scores "[5,6,4]" --scale 7-point
526
+ wjx analytics anomalies --responses '[...]' # 异常答卷检测
527
+ wjx analytics compare --set_a '{"score":80}' --set_b '{"score":90}'
528
+ wjx analytics decode-push --payload "..." --app_key "key"
529
+ ```
530
+
531
+ | 子命令 | 选项 | 必填 | 类型 | 说明 |
532
+ |--------|------|:----:|------|------|
533
+ | **decode** | `--submitdata` | **是** | string | 提交数据字符串 |
534
+ | **nps** | `--scores` | **是** | json | 评分 JSON 数组(0-10) |
535
+ | **csat** | `--scores` | **是** | json | 评分 JSON 数组 |
536
+ | | `--scale` | | string | 量表类型:`5-point` 或 `7-point`(默认 5-point) |
537
+ | **anomalies** | `--responses` | **是** | json | 答卷数据 JSON 数组 |
538
+ | **compare** | `--set_a` | **是** | json | 指标集 A JSON 对象 |
539
+ | | `--set_b` | **是** | json | 指标集 B JSON 对象 |
540
+ | **decode-push** | `--payload` | **是** | string | 加密推送数据 |
541
+ | | `--app_key` | **是** | string | AppKey |
542
+ | | `--signature` | | string | 签名 |
543
+ | | `--raw_body` | | string | 原始请求体 |
544
+
545
+ ### 配置与诊断
546
+
547
+ ```bash
548
+ wjx init # 交互式引导配置(API Key、Base URL、Corp ID → ~/.wjxrc)
549
+ wjx whoami # 验证 API Key 并显示账号信息
550
+ wjx doctor # 环境诊断(配置文件、Node 版本、API Key、API 连接、SDK 版本)
551
+ ```
552
+
553
+ ---
554
+
555
+ ## stdin 管道输入
556
+
557
+ 通过 `--stdin` 标志从管道读取 JSON 参数。CLI 显式指定的选项优先于 stdin 中的同名字段(source-aware merge)。
558
+
559
+ ```bash
560
+ # 基本用法
561
+ echo '{"vid": 12345}' | wjx --stdin survey get
562
+
563
+ # 多字段
564
+ echo '{"page": 1, "page_size": 20}' | wjx --stdin survey list
565
+
566
+ # CLI 参数覆盖 stdin(source-aware:只有 CLI 显式指定的值才会覆盖)
567
+ echo '{"vid": 12345, "state": 1}' | wjx --stdin survey status --state 2
568
+ # → state=2(CLI 显式指定),vid=12345(来自 stdin)
569
+
570
+ # 配合 jq 链式调用
571
+ wjx survey list | jq '.data[0].vid' | xargs -I{} wjx survey get --vid {}
572
+
573
+ # Agent 工作流:先查问卷,再导出文本
574
+ VID=$(wjx survey list | jq -r '.data.activitys | to_entries[0].value.vid')
575
+ wjx survey export-text --vid "$VID" --raw
576
+ ```
577
+
578
+ **规则:**
579
+ - stdin 必须是 JSON 对象(不能是数组或原始值)
580
+ - 空 stdin 不报错,等同于不使用 `--stdin`
581
+ - 非法 JSON → `INPUT_ERROR` exit 2
582
+
583
+ ---
584
+
585
+ ## 输出格式
586
+
587
+ ### JSON(默认)
588
+
589
+ 成功时输出到 stdout:
590
+
591
+ ```bash
592
+ $ wjx survey url --mode create
593
+ {
594
+ "url": "https://www.wjx.cn/..."
595
+ }
596
+ ```
597
+
598
+ ### 表格
599
+
600
+ ```bash
601
+ $ wjx --table survey list
602
+ ┌─────────┬───────┬──────────────┬────────┐
603
+ │ (index) │ vid │ title │ status │
604
+ ├─────────┼───────┼──────────────┼────────┤
605
+ │ 0 │ 12345 │ '客户满意度' │ 1 │
606
+ └─────────┴───────┴──────────────┴────────┘
607
+ ```
608
+
609
+ ### 错误
610
+
611
+ 错误输出到 **stderr**(stdout 为空),详见下方 [错误协议](#错误协议)。
612
+
613
+ ---
614
+
615
+ ## 错误协议
616
+
617
+ wjx-cli 使用结构化 JSON 错误输出,方便 AI Agent 和自动化脚本解析。
618
+
619
+ ### stderr JSON Schema
620
+
621
+ ```json
622
+ {
623
+ "error": true,
624
+ "message": "错误描述(人类可读)",
625
+ "code": "API_ERROR | AUTH_ERROR | INPUT_ERROR",
626
+ "exitCode": 1
627
+ }
628
+ ```
629
+
630
+ | 字段 | 类型 | 说明 |
631
+ |------|------|------|
632
+ | `error` | `boolean` | 恒为 `true` |
633
+ | `message` | `string` | 错误描述 |
634
+ | `code` | `string` | 错误分类(见下表) |
635
+ | `exitCode` | `number` | 进程退出码 |
636
+
637
+ ### 退出码
638
+
639
+ | 退出码 | 错误码 | 含义 | 典型场景 |
640
+ |:------:|--------|------|----------|
641
+ | **0** | | 成功 | 命令正常完成 |
642
+ | **1** | `API_ERROR` | API 错误 | 网络错误、API 返回失败 |
643
+ | **1** | `AUTH_ERROR` | 认证错误 | API Key 缺失或无效 |
644
+ | **2** | `INPUT_ERROR` | 输入错误 | 缺少必填参数、无效整数、JSON 解析失败 |
645
+
646
+ ### 示例
647
+
648
+ ```bash
649
+ # 缺少 API Key → exit 1, AUTH_ERROR
650
+ $ wjx survey list 2>&1 >/dev/null
651
+ {"error":true,"message":"WJX_API_KEY 未设置。请通过 --api-key 参数、WJX_API_KEY 环境变量、或运行 wjx init 配置。","code":"AUTH_ERROR","exitCode":1}
652
+
653
+ # 缺少必填参数 → exit 2, INPUT_ERROR
654
+ $ wjx survey get 2>&1 >/dev/null
655
+ {"error":true,"message":"Missing required option: --vid","code":"INPUT_ERROR","exitCode":2}
656
+
657
+ # 无效整数 exit 2, INPUT_ERROR
658
+ $ wjx survey get --vid abc 2>&1 >/dev/null
659
+ {"error":true,"message":"Invalid integer: \"abc\"","code":"INPUT_ERROR","exitCode":2}
660
+ ```
661
+
662
+ ### Agent 错误处理模式
663
+
664
+ ```python
665
+ import subprocess, json
666
+
667
+ result = subprocess.run(["wjx", "survey", "get", "--vid", "12345"],
668
+ capture_output=True, text=True)
669
+
670
+ if result.returncode == 0:
671
+ data = json.loads(result.stdout)
672
+ elif result.returncode == 2:
673
+ # 输入错误 — 修正参数后重试
674
+ err = json.loads(result.stderr)
675
+ print(f"Bad input: {err['message']}")
676
+ elif result.returncode == 1:
677
+ # API/认证错误 — 检查 API Key 或稍后重试
678
+ err = json.loads(result.stderr)
679
+ print(f"API error: {err['message']}")
680
+ ```
681
+
682
+ ---
683
+
684
+ ## Agent 集成指南
685
+
686
+ wjx-cli 的设计目标是成为 AI Agent 的问卷星 API 操作工具。以下是典型集成模式。
687
+
688
+ ### 作为 LLM Tool 使用
689
+
690
+ ```json
691
+ {
692
+ "type": "function",
693
+ "function": {
694
+ "name": "wjx_survey_list",
695
+ "description": "列出问卷星中的所有问卷",
696
+ "parameters": {
697
+ "type": "object",
698
+ "properties": {
699
+ "page": { "type": "integer", "description": "页码" },
700
+ "page_size": { "type": "integer", "description": "每页数量" }
701
+ }
702
+ }
703
+ }
704
+ }
705
+ ```
706
+
707
+ Agent 实现:
708
+
709
+ ```python
710
+ def execute_wjx_tool(name, args):
711
+ cmd = ["wjx"] + name.replace("wjx_", "").replace("_", " ").split()
712
+ for k, v in args.items():
713
+ cmd.extend([f"--{k}", str(v)])
714
+ result = subprocess.run(cmd, capture_output=True, text=True)
715
+ return json.loads(result.stdout) if result.returncode == 0 \
716
+ else json.loads(result.stderr)
717
+ ```
718
+
719
+ ### stdin pipe 批量操作
720
+
721
+ ```bash
722
+ # 批量查询多个问卷的答卷数
723
+ for vid in 12345 12346 12347; do
724
+ echo "{\"vid\": $vid}" | wjx --stdin response count
725
+ done
726
+
727
+ # 结合 jq 构造复杂参数
728
+ echo '{"title":"调查","type":0,"questions":"[]"}' | wjx --stdin survey create
729
+ ```
730
+
731
+ ### 与 wjx-mcp-server 的关系
732
+
733
+ | 场景 | 推荐工具 |
734
+ |------|----------|
735
+ | Claude Desktop / Cursor MCP 客户端 | `wjx-mcp-server` |
736
+ | 终端 / shell 脚本 / CI/CD | `wjx-cli` |
737
+ | 自定义 Agent(Python/Node/Go) | `wjx-cli`(子进程)或 `wjx-api-sdk`(直接导入) |
738
+ | 需要 56 MCP tools + resources + prompts | `wjx-mcp-server` |
739
+ | 需要简单的 JSON in / JSON out | `wjx-cli` |
740
+
741
+ ---
742
+
743
+ ## 环境变量
744
+
745
+ | 变量 | 必填 | 说明 | 默认值 |
746
+ |------|:----:|------|--------|
747
+ | `WJX_API_KEY` | 是* | 问卷星 OpenAPI API Key | — |
748
+ | `WJX_CORP_ID` | 否 | 企业通讯录 ID(通讯录相关操作需要) | — |
749
+ | `WJX_BASE_URL` | 否 | 自定义 API 基础域名 | `https://www.wjx.cn` |
750
+
751
+ \* SSO analytics 命令不需要 API Key。
752
+
753
+ 以上环境变量也可以通过 `wjx init` 写入 `~/.wjxrc` 配置文件,CLI 启动时自动加载。凭据解析优先级:`--api-key` 参数 > 环境变量 > 配置文件。
754
+
755
+ ---
756
+
757
+ ## 开发
758
+
759
+ ```bash
760
+ cd wjx-ai-kit/wjx-cli
761
+
762
+ npm run build # TypeScript 编译 → dist/
763
+ npm test # 构建 + 运行 82 个测试
764
+ npm run clean # 清理 dist/
765
+
766
+ # 手动测试
767
+ node dist/index.js --help
768
+ node dist/index.js survey url --mode create
769
+ WJX_API_KEY=xxx node dist/index.js survey list
770
+ ```
771
+
772
+ ### 项目结构
773
+
774
+ ```
775
+ src/
776
+ ├── index.ts # 入口 + Commander program
777
+ ├── commands/ # 12 个命令模块
778
+ │ └── *.ts # 每个文件导出 register*Commands(program)
779
+ └── lib/
780
+ ├── config.ts # ~/.wjxrc 配置文件读写
781
+ ├── command-helpers.ts # executeCommand / strictInt / requireField
782
+ ├── auth.ts # API Key 获取(--api-key > env > config)
783
+ ├── output.ts # JSON / table 输出
784
+ ├── errors.ts # CliError + 退出码路由
785
+ └── stdin.ts # stdin 读取 + source-aware merge
786
+ ```
787
+
788
+ ### 添加新命令
789
+
790
+ 1. 在 `wjx-api-sdk` 中确认 SDK 函数已导出
791
+ 2. 创建 `src/commands/<module>.ts`,导出 `register<Module>Commands(program)`
792
+ 3. 在 `src/index.ts` 中注册
793
+ 4. 在 `__tests__/cli.test.mjs` 中添加测试
794
+ 5. `npm test` 验证
795
+
796
+ ---
797
+
798
+ ## 常见问题
799
+
800
+ ### `AUTH_ERROR: WJX_API_KEY 未设置`
801
+
802
+ 运行交互式配置,或手动设置环境变量:
803
+
804
+ ```bash
805
+ wjx init # 交互式配置(推荐)
806
+ #
807
+ export WJX_API_KEY=your_api_key # 环境变量
808
+ # 或
809
+ wjx --api-key your_api_key survey list # 命令行参数
810
+ ```
811
+
812
+ ### `INPUT_ERROR: Invalid integer: "abc"`
813
+
814
+ 整数参数必须是纯数字,不接受 `123abc` 或 `12.5` 等值。
815
+
816
+ ### `INPUT_ERROR: stdin JSON must be an object`
817
+
818
+ `--stdin` 只接受 JSON 对象,不接受数组或原始值:
819
+
820
+ ```bash
821
+ # 错误
822
+ echo '[1,2,3]' | wjx --stdin survey list
823
+
824
+ # 正确
825
+ echo '{"page":1}' | wjx --stdin survey list
826
+ ```
827
+
828
+ ### API 连接问题
829
+
830
+ 运行诊断:
831
+
832
+ ```bash
833
+ wjx doctor
834
+ ```
835
+
836
+ 如需指向测试环境:
837
+
838
+ ```bash
839
+ export WJX_BASE_URL=https://your-test-server.com
840
+ ```
841
+
842
+ ---
843
+
844
+ ## 相关项目
845
+
846
+ | 项目 | 说明 |
847
+ |------|------|
848
+ | [wjx-ai-kit](../) | Monorepo 根目录 |
849
+ | [wjx-api-sdk](../wjx-api-sdk/) | TypeScript SDK(50+ 函数,零依赖) |
850
+ | [wjx-mcp-server](../wjx-mcp-server/) | MCP Server(56 tools,供 Claude/Cursor 使用) |
851
+
852
+ ---
853
+
854
+ ## 许可证
855
+
856
+ [MIT](LICENSE)