@wukongcrm/mcp-server 0.1.3 → 0.1.4

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,146 +1,175 @@
1
- # @wukongcrm/mcp-server
1
+ # wukong-mcp
2
2
 
3
- WukongCRM MCP Server,用于给支持 Model Context Protocol 的本地 AI 客户端提供 CRM 查询和受控写入能力。
4
-
5
- 默认代理 `https://www.72crm.com/api-11/` 下的固定白名单接口,不提供任意 URL 透传。
3
+ 本项目是供本地 AI ChatGPT 网页端使用的 72CRM MCP Server,固定代理 `https://www.72crm.com/api-11/` 的白名单接口。
6
4
 
7
5
  ## 特点
8
6
 
9
- - 通过 `CRM_API_KEY` 登录,MCP 进程内部调用 `/login` 换取 `adminToken`。
10
- - 业务请求按 72CRM 要求发送 `Admin-Token` 请求头,token 只缓存在本地进程内存中。
7
+ - 本地 stdio 模式由用户配置 `CRM_API_KEY`;远程 HTTP 模式通过当前 72CRM 登录用户静默生成专用 API Key。
8
+ - 业务请求仍按 72CRM 要求发送 `Admin-Token` 请求头,该 token 只缓存在本地进程内存中。
9
+ - 远程模式不会把 API Key 暴露给 ChatGPT 模型,也不会把 API Key 明文写入服务端数据文件。
11
10
  - API Key 登录使用独立端类型 `type=4`,避免占用 PC 端 `type=1` 登录态。
12
11
  - 不读取 OpenAPI,不调用 `/v3/api-docs`。
13
12
  - 不支持附件上传、删除、下载流代理。
14
13
  - 查询能力覆盖线索、客户、联系人、商机、产品、合同、回款、发票、跟进记录等模块。
15
- - 写入只开放线索、客户、联系人、商机、跟进记录,并且必须传 `confirm=true`。
16
-
17
- ## 通用 MCP 配置
14
+ - 人力资源 HRM 保留员工、部门、岗位、考勤、请假等查询,并开放 HRM 域内固定路径写入。
15
+ - 独立财务 FM 保留凭证、账簿、报表、科目、币别、凭证字、仪表盘查询,并开放 FM 域内固定路径写入。
16
+ - 进销存 JXC 保留产品、供应商、仓库、库存和出入库明细查询,并开放 JXC 域内固定路径写入。
17
+ - 所有写入仍必须传 `confirm=true`;未确认时只返回预览,不调用 72CRM 写接口。
18
18
 
19
- 推荐直接通过 `npx` 启动,无需提前全局安装:
20
-
21
- ```json
22
- {
23
- "mcpServers": {
24
- "wukongcrm": {
25
- "type": "stdio",
26
- "command": "npx",
27
- "args": ["-y", "@wukongcrm/mcp-server"],
28
- "env": {
29
- "CRM_BASE_URL": "https://www.72crm.com/api-11/",
30
- "CRM_API_KEY": "你的 72CRM API Key"
31
- }
32
- }
33
- }
34
- }
35
- ```
19
+ ## ChatGPT 网页端(远程 MCP)
36
20
 
37
- 如果你的 MCP 客户端不支持 `type` 字段,可以去掉它:
21
+ ChatGPT 网页端不能启动本地 `stdio` 进程,也不支持在 MCP 配置中直接填写自定义 API Key。远程模式提供 Streamable HTTP MCP 和 OAuth 2.0:用户第一次连接时跳转到 72CRM;绑定页通过当前浏览器 `localStorage` 中的 `Admin-Token` 静默生成一把独立 MCP API Key,再通过一次性绑定码由服务端交换。wukong-mcp 验证该 Key 后,签发包含加密 API Key 的短期访问令牌和可轮换刷新令牌。
38
22
 
39
- ```json
40
- {
41
- "mcpServers": {
42
- "wukongcrm": {
43
- "command": "npx",
44
- "args": ["-y", "@wukongcrm/mcp-server"],
45
- "env": {
46
- "CRM_BASE_URL": "https://www.72crm.com/api-11/",
47
- "CRM_API_KEY": "你的 72CRM API Key"
48
- }
49
- }
50
- }
51
- }
52
- ```
23
+ 绑定请求明确不携带 Cookie,`Admin-Token` 也不会传给 wukong-mcp。远程模式不要配置公共的 `CRM_API_KEY`,否则所有 ChatGPT 用户会共用同一个 CRM 账号。
53
24
 
54
- ## pnpm 使用
25
+ ### 启动配置
55
26
 
56
- 不要求必须使用 npm。支持通过 `pnpm dlx` 启动:
27
+ 复制示例配置并填写两个不同用途的随机密钥:
57
28
 
58
- ```json
59
- {
60
- "mcpServers": {
61
- "wukongcrm": {
62
- "type": "stdio",
63
- "command": "pnpm",
64
- "args": ["dlx", "@wukongcrm/mcp-server"],
65
- "env": {
66
- "CRM_BASE_URL": "https://www.72crm.com/api-11/",
67
- "CRM_API_KEY": "你的 72CRM API Key"
68
- }
69
- }
70
- }
71
- }
29
+ ```bash
30
+ cp .env.example .env
31
+ chmod +x start-http.sh
32
+ ./start-http.sh
72
33
  ```
73
34
 
74
- ## 全局安装
35
+ 也可以传入其他配置文件:
75
36
 
76
37
  ```bash
77
- npm install -g @wukongcrm/mcp-server
38
+ ./start-http.sh /path/to/wukong-mcp.env
78
39
  ```
79
40
 
80
- 安装后可以直接启动:
41
+ 脚本默认在每次启动前执行 `npm run build`,并通过 `exec node dist/http-entry.js` 保持前台运行。已经构建完成时,可以在配置文件中设置 `WUKONG_MCP_BUILD_ON_START=0`。
42
+
43
+ 生产环境关键变量如下:
81
44
 
82
45
  ```bash
83
- CRM_API_KEY="你的 72CRM API Key" \
84
- CRM_BASE_URL="https://www.72crm.com/api-11/" \
85
- wukongcrm-mcp
86
- ```
46
+ MCP_PUBLIC_URL=https://www.72crm.com/mcp
47
+ MCP_OAUTH_SECRET=<单独生成的至少32字符随机密钥>
48
+ MCP_DATA_DIR=/var/lib/wukong-mcp
87
49
 
88
- 对应 MCP 配置:
50
+ CRM_BASE_URL=https://www.72crm.com/api-11/
51
+ CRM_BINDING_AUTHORIZE_URL=https://www.72crm.com/mcp-binding.html
52
+ CRM_BINDING_EXCHANGE_URL=https://www.72crm.com/api-11/adminMcpBinding/exchange
53
+ CRM_BINDING_CALLBACK_URL=https://www.72crm.com/mcp/oauth/72crm/callback
54
+ CRM_BINDING_CLIENT_ID=wukong-mcp
55
+ CRM_BINDING_CLIENT_SECRET=<与72CRM后端完全一致的至少32字符共享密钥>
89
56
 
90
- ```json
91
- {
92
- "mcpServers": {
93
- "wukongcrm": {
94
- "type": "stdio",
95
- "command": "wukongcrm-mcp",
96
- "env": {
97
- "CRM_BASE_URL": "https://www.72crm.com/api-11/",
98
- "CRM_API_KEY": "你的 72CRM API Key"
99
- }
100
- }
101
- }
102
- }
57
+ MCP_HOST=127.0.0.1
58
+ MCP_PORT=3000
59
+ MCP_ALLOWED_HOSTS=www.72crm.com
60
+ MCP_TRUST_PROXY=1
103
61
  ```
104
62
 
105
- ## API Key 配置
63
+ - `MCP_OAUTH_SECRET` 用于 AES-256-GCM 加密 OAuth 令牌;更换后,已连接用户需要重新授权。
64
+ - `MCP_DATA_DIR` 保存动态 OAuth 客户端和撤销记录,不保存明文 API Key。
65
+ - `CRM_BINDING_AUTHORIZE_URL` 必须指向 72CRM 前端中转页,不能直接填写后端授权接口。
66
+ - `CRM_BINDING_CLIENT_SECRET` 必须与 72CRM `admin-web` 配置完全一致,只保存在服务端。
67
+ - `CRM_BINDING_CALLBACK_URL` 默认根据 `MCP_PUBLIC_URL` 的路径生成,显式配置时必须与其同域。
68
+ - `MCP_ALLOWED_HOSTS` 是逗号分隔的额外 Host 白名单;公开域名会由 `MCP_PUBLIC_URL` 自动加入。
69
+ - `MCP_TRUST_PROXY=1` 表示 MCP 服务前面有一层可信 Nginx 反向代理,使 Express 能正确读取客户端 IP 并避免限流器把所有请求识别为 Nginx;直接暴露 MCP 端口时应设置为 `false`,也可以填写可信代理 IP/CIDR。
70
+ - MCP 的初始 Bearer challenge 同时要求 `crm.read offline_access`,ChatGPT 完成授权后会获得刷新令牌;已经按旧范围授权的连接需要删除后重新连接。
71
+ - 动态 OAuth 客户端只支持 `none + PKCE` 公共客户端模式,不签发客户端密钥,以兼容 ChatGPT 和 Claude 的远程 MCP 授权流程。
106
72
 
107
- `CRM_API_KEY` 是运行时环境变量,不应在 `npm install` 阶段传入。
73
+ 远程端点布局:
108
74
 
109
- README 中示例里的 `CRM_API_KEY` 对应 72CRM 个人中心生成的 MCP Token。获取地址:
75
+ - MCP:`https://www.72crm.com/mcp`
76
+ - 健康检查:`https://www.72crm.com/mcp/healthz`
77
+ - OAuth:`/mcp/oauth/authorize`、`/mcp/oauth/token`、`/mcp/oauth/register`、`/mcp/oauth/revoke`
78
+ - 72CRM 回调:`/mcp/oauth/72crm/callback`
79
+ - 标准发现:`/.well-known/oauth-protected-resource/mcp`、`/.well-known/oauth-authorization-server`、`/.well-known/openid-configuration`
110
80
 
111
- ```text
112
- https://www.72crm.com/cloud/#/person/index?selectedIndex=1
81
+ ### 72CRM 配置
82
+
83
+ `admin-web` 需要配置:
84
+
85
+ ```bash
86
+ WUKONG_MCP_BINDING_CLIENT_ID=wukong-mcp
87
+ WUKONG_MCP_BINDING_CLIENT_SECRET=<与MCP服务一致的共享密钥>
88
+ WUKONG_MCP_BINDING_CALLBACK_URL=https://www.72crm.com/mcp/oauth/72crm/callback
89
+ WUKONG_MCP_BINDING_CODE_TTL_SECONDS=120
113
90
  ```
114
91
 
115
- MCP 客户端启动 server 时必须能把 `CRM_API_KEY` 注入到 `@wukongcrm/mcp-server` 进程环境中。常见方式是写在 MCP 客户端配置的 `env` 字段里,或由启动脚本/系统环境变量注入。
92
+ `mcp-binding.html` 72CRM 前端的 `localStorage["Admin-Token"]` 读取当前登录 Token,以 `Admin-Token` 请求头调用后端,并明确禁止携带 Cookie。Token 只用于本次绑定,不会发给 wukong-mcp。交换接口使用时间戳和 HMAC-SHA256 签名,一次性绑定码只能消费一次。
93
+
94
+ ### 在 ChatGPT 中加载
95
+
96
+ 1. 在 ChatGPT 设置中启用开发者模式,并创建自定义 App/Connector。
97
+ 2. MCP Server URL 填写 `https://www.72crm.com/mcp`,认证方式选择 OAuth。
98
+ 3. 保存并连接后,浏览器会跳转到 `https://www.72crm.com/mcp-binding.html`;当前已登录时将静默完成绑定。
99
+ 4. 授权完成后扫描工具,检查各工具的只读、写入和破坏性标记。
116
100
 
117
101
  ## 开发运行
118
102
 
119
- ```bash
120
- npm install
121
- CRM_API_KEY="你的 72CRM API Key" \
122
- CRM_BASE_URL="https://www.72crm.com/api-11/" \
103
+ ```powershell
104
+ cd D:\Desktop\wukong-mcp
105
+ npm ci
106
+ $env:CRM_API_KEY="你的 72CRM API Key"
107
+ $env:CRM_BASE_URL="https://www.72crm.com/api-11/"
123
108
  npm run build
124
109
  node dist/index.js
125
110
  ```
126
111
 
127
- ## 发布
112
+ ## 打包分发
128
113
 
129
- 发布前验证:
114
+ 发布到 npm 前,先完成依赖安装和测试:
130
115
 
131
- ```bash
116
+ ```powershell
117
+ cd D:\Desktop\wukong-mcp
118
+ npm ci
132
119
  npm test
133
120
  npm run build
134
- npm pack --dry-run
121
+ npm publish
135
122
  ```
136
123
 
137
- 首次公开发布 scoped 包:
124
+ 包使用 `@wukongcrm/mcp-server` 作用域公开发布。使用者可以直接安装:
138
125
 
139
- ```bash
140
- npm publish
126
+ ```powershell
127
+ npm install -g @wukongcrm/mcp-server
128
+ ```
129
+
130
+ 如需离线分发,可以在本机生成 npm tarball:
131
+
132
+ ```powershell
133
+ npm pack
134
+ ```
135
+
136
+ 生成文件示例:
137
+
138
+ ```text
139
+ wukongcrm-mcp-server-0.1.4.tgz
141
140
  ```
142
141
 
143
- `package.json` 已配置 `publishConfig.access=public`,因此不需要额外追加 `--access public`。
142
+ 这个包只包含运行所需的 `dist`、`README.md` `package.json`,不会携带源码、测试文件或用户 API Key。
143
+
144
+ 使用者拿到 `.tgz` 后安装:
145
+
146
+ ```powershell
147
+ npm install -g .\wukongcrm-mcp-server-0.1.4.tgz
148
+ ```
149
+
150
+ 安装后可以直接用命令启动:
151
+
152
+ ```powershell
153
+ $env:CRM_API_KEY="使用者自己的 72CRM API Key"
154
+ $env:CRM_BASE_URL="https://www.72crm.com/api-11/"
155
+ wukong-mcp
156
+ ```
157
+
158
+ ## 本地 AI 配置示例
159
+
160
+ ```json
161
+ {
162
+ "mcpServers": {
163
+ "wukong-crm": {
164
+ "command": "wukong-mcp",
165
+ "env": {
166
+ "CRM_BASE_URL": "https://www.72crm.com/api-11/",
167
+ "CRM_API_KEY": "请在这里填写 72CRM API Key"
168
+ }
169
+ }
170
+ }
171
+ }
172
+ ```
144
173
 
145
174
  ## 支持工具
146
175
 
@@ -156,16 +185,137 @@ npm publish
156
185
  - `crm_get_record_timeline`
157
186
  - `crm_get_action_records`
158
187
  - `crm_list_files`
188
+ - `crm_search_products`
189
+ - `crm_search_sale_products`
190
+ - `crm_get_product`
191
+ - `crm_get_product_information`
192
+ - `crm_get_product_schema`
193
+ - `crm_list_product_files`
194
+ - `crm_get_product_num`
195
+ - `crm_get_simple_products`
159
196
  - `crm_list_users`
160
197
  - `crm_find_user_id`
161
198
  - `crm_list_departments`
162
199
  - `crm_find_dept_id`
200
+ - `crm_list_address_book_contacts`
201
+ - `crm_get_address_book_contact`
202
+ - `crm_list_address_book_departments`
203
+ - `crm_list_address_book_auth_departments`
204
+ - `crm_list_address_book_dept_user_ids`
205
+ - `crm_list_address_book_dept_users`
206
+ - `crm_list_address_book_auth_users`
207
+ - `crm_get_address_book_user_dept_role_info`
208
+ - `crm_get_address_book_organization`
209
+ - `crm_get_address_book_user_count`
210
+ - `crm_toggle_address_book_attention`
211
+ - `crm_list_hrm_employees`
212
+ - `crm_get_hrm_employee`
213
+ - `crm_list_hrm_employee_fields`
214
+ - `crm_list_hrm_departments`
215
+ - `crm_get_hrm_department`
216
+ - `crm_list_hrm_department_employees`
217
+ - `crm_get_hrm_employee_post`
218
+ - `crm_list_hrm_attendance_month_records`
219
+ - `crm_get_hrm_attendance_daily_detail`
220
+ - `crm_list_hrm_leave_records`
221
+ - `crm_list_hrm_leave_types`
222
+ - `crm_write_hrm`
223
+ - `crm_create_hrm_record`
224
+ - `crm_update_hrm_record`
225
+ - `crm_list_finance_modules`
226
+ - `crm_search_finance_vouchers`
227
+ - `crm_get_finance_voucher`
228
+ - `crm_summarize_finance_vouchers`
229
+ - `crm_query_finance_ledger`
230
+ - `crm_query_finance_report`
231
+ - `crm_list_finance_subjects`
232
+ - `crm_list_finance_currencies`
233
+ - `crm_list_finance_voucher_words`
234
+ - `crm_query_finance_dashboard`
235
+ - `crm_write_finance`
236
+ - `crm_create_finance_voucher`
237
+ - `crm_update_finance_voucher`
238
+ - `crm_list_jxc_modules`
239
+ - `crm_search_jxc_records`
240
+ - `crm_get_jxc_record`
241
+ - `crm_get_jxc_record_information`
242
+ - `crm_get_jxc_module_schema`
243
+ - `crm_list_jxc_files`
244
+ - `crm_list_jxc_stock_products`
245
+ - `crm_get_jxc_product_inventory`
246
+ - `crm_list_jxc_stock_movements`
247
+ - `crm_get_jxc_warehouse_product_stock`
248
+ - `crm_get_jxc_warehouse_names`
249
+ - `crm_write_jxc`
250
+ - `crm_create_jxc_record`
251
+ - `crm_update_jxc_record`
252
+ - `crm_list_calendar_events`
253
+ - `crm_get_calendar_event`
254
+ - `crm_list_oa_examine_categories`
255
+ - `crm_list_oa_examine_groups`
256
+ - `crm_list_oa_examines`
257
+ - `crm_get_oa_examine`
258
+ - `crm_get_oa_examine_fields`
259
+ - `crm_list_oa_examine_record_logs`
260
+ - `crm_list_oa_examine_flow_records`
261
+ - `crm_list_oa_announcements`
262
+ - `crm_get_oa_announcement`
263
+ - `crm_create_oa_announcement`
264
+ - `crm_update_oa_announcement`
265
+ - `crm_delete_oa_announcement`
266
+ - `crm_mark_oa_announcement_read`
267
+ - `crm_list_oa_logs`
268
+ - `crm_get_oa_log`
269
+ - `crm_get_oa_log_information`
270
+ - `crm_list_oa_log_templates`
271
+ - `crm_get_oa_log_fields`
272
+ - `crm_get_oa_log_welcome`
273
+ - `crm_get_oa_log_bulletin`
274
+ - `crm_get_oa_log_complete_stats`
275
+ - `crm_list_oa_log_complete_records`
276
+ - `crm_list_oa_log_incomplete_records`
277
+ - `crm_list_oa_tasks`
278
+ - `crm_list_related_oa_tasks`
163
279
  - `crm_preview_write`
164
280
  - `crm_create_record`
165
281
  - `crm_update_customer`
166
282
  - `crm_update_record_fields`
283
+ - `crm_create_product`
284
+ - `crm_update_product`
285
+ - `crm_update_product_fields`
286
+ - `crm_update_product_status`
287
+ - `crm_transfer_products_owner`
288
+ - `crm_delete_products`
289
+ - `crm_create_contract`
290
+ - `crm_update_contract`
291
+ - `crm_create_receivables`
292
+ - `crm_update_receivables`
293
+ - `crm_create_receivables_plan`
294
+ - `crm_update_receivables_plan`
295
+ - `crm_create_invoice`
296
+ - `crm_update_invoice`
297
+ - `crm_create_quotation`
298
+ - `crm_update_quotation`
299
+ - `crm_create_calendar_event`
300
+ - `crm_update_calendar_event`
301
+ - `crm_create_oa_examine`
302
+ - `crm_save_oa_examine_draft`
303
+ - `crm_audit_oa_examine`
304
+ - `crm_batch_audit_oa_examine`
305
+ - `crm_create_oa_log`
306
+ - `crm_update_oa_log`
307
+ - `crm_delete_oa_log`
308
+ - `crm_toggle_oa_log_favour`
309
+ - `crm_create_oa_task`
310
+ - `crm_update_oa_task_fields`
167
311
  - `crm_add_followup`
168
312
  - `crm_update_followup`
313
+ - `workorder_search_records`
314
+ - `workorder_get_record`
315
+ - `workorder_get_schema`
316
+ - `workorder_preview_write`
317
+ - `workorder_create_record`
318
+ - `workorder_update_record`
169
319
 
170
320
  ### `crm_search_records` 语义搜索
171
321
 
@@ -182,6 +332,50 @@ npm publish
182
332
 
183
333
  客户模块会转换为“客户名称 / 手机 / 电话”三个高级筛选条件,使用 `type=3`(包含)和不同 `groupId` 做 OR 查询。也支持 `query`、`q`、`phone`、`mobile`、`name` 等字段。
184
334
 
335
+ 负责人和创建人可以直接传用户 ID。单个和多个 ID 分别使用 `ownerUserId` / `ownerUserIds`、`createUserId` / `createUserIds`:
336
+
337
+ ```json
338
+ {
339
+ "module": "customer",
340
+ "ownerUserIds": [9, 10],
341
+ "createUserId": 11
342
+ }
343
+ ```
344
+
345
+ 只有昵称时,可以使用 `ownerUserName` / `ownerUserNames`、`createUserName` / `createUserNames`。MCP 会先调用员工列表接口做模糊召回,再按昵称精确比对;唯一命中后才把用户 ID 写入 `formType=user` 的筛选值。查无此人会报错,重名时会列出候选用户 ID,必须改传明确 ID,避免筛错人:
346
+
347
+ ```json
348
+ {
349
+ "module": "customer",
350
+ "ownerUserName": "张三"
351
+ }
352
+ ```
353
+
354
+ 通用高级筛选也支持相同的昵称解析。以下调用最终发送给 72CRM 的 `values` 会是用户 ID,而不是昵称:
355
+
356
+ ```json
357
+ {
358
+ "module": "customer",
359
+ "filters": [
360
+ {
361
+ "fieldName": "ownerUserId",
362
+ "formType": "user",
363
+ "type": 1,
364
+ "values": ["张三"]
365
+ }
366
+ ]
367
+ }
368
+ ```
369
+
370
+ 如需单独核对用户 ID,可调用 `crm_find_user_id`:
371
+
372
+ ```json
373
+ {
374
+ "name": "张三",
375
+ "mode": "realname"
376
+ }
377
+ ```
378
+
185
379
  ### 客户更新
186
380
 
187
381
  推荐优先使用 `crm_update_customer` 修改客户字段。它支持直接传客户 ID,也支持通过手机号、客户名或关键字唯一匹配客户;正式写入前会读取客户字段结构,自动补齐 `fieldId`、`fieldType`、`type`、`formType`,避免下拉字段或自定义字段写错结构。
@@ -214,6 +408,655 @@ npm publish
214
408
 
215
409
  写入成功后默认会再次读取 `/crmCustomer/information/{id}` 做字段级校验;如只想写入不校验,可传 `verify=false`。
216
410
 
411
+ ### CRM 产品
412
+
413
+ 产品模块同时支持通用 CRM 读接口和专用产品工具。产品列表固定调用 `/crmProduct/queryPageList`,销售产品列表固定调用 `/crmProduct/querySaleProductPageList`:
414
+
415
+ ```json
416
+ {
417
+ "page": 1,
418
+ "limit": 20,
419
+ "keyword": "云服务",
420
+ "categoryId": 5,
421
+ "status": 1
422
+ }
423
+ ```
424
+
425
+ 详情、详情页字段、字段结构、附件元数据、数量和简要实体分别调用:
426
+
427
+ - `/crmProduct/queryById/{productId}`
428
+ - `/crmProduct/information/{productId}`
429
+ - `/crmProduct/field` 或 `/crmProduct/field/{productId}`
430
+ - `/crmProduct/queryFileList`
431
+ - `/crmProduct/num`
432
+ - `/crmProduct/querySimpleEntity`
433
+
434
+ 产品新增和编辑可以直接传 72CRM 保存 payload,也可以使用 `entity + field`:
435
+
436
+ ```json
437
+ {
438
+ "entity": {
439
+ "name": "云服务"
440
+ },
441
+ "field": [],
442
+ "confirm": true
443
+ }
444
+ ```
445
+
446
+ `crm_create_product` 固定调用 `/crmProduct/add`,`crm_update_product` 固定调用 `/crmProduct/update`,编辑时必须提供 `productId` 或 `id`。字段更新使用 `crm_update_product_fields`,固定调用 `/crmProduct/updateInformation`,会先读取 `/crmProduct/field/{productId}` 自动补齐字段结构,并默认读取 `/crmProduct/information/{productId}` 做写后校验。
447
+
448
+ 上下架、负责人转移和删除分别调用 `/crmProduct/updateStatus`、`/crmProduct/changeOwnerUser`、`/crmProduct/deleteByIds`,这些写入都必须传 `confirm=true`。导入导出、multipart 上传和文件流下载仍不代理。
449
+
450
+ ### CRM 审批单据写入
451
+
452
+ 合同、回款、回款计划、发票、报价单不再走通用 `crm_create_record`,而是使用专用工具绑定真实固定接口:
453
+
454
+ - 合同:`crm_create_contract` -> `/crmContract/add`,`crm_update_contract` -> `/crmContract/update`
455
+ - 回款:`crm_create_receivables` -> `/crmReceivables/add`,`crm_update_receivables` -> `/crmReceivables/update`
456
+ - 回款计划:`crm_create_receivables_plan` -> `/crmReceivablesPlan/add`,`crm_update_receivables_plan` -> `/crmReceivablesPlan/update`
457
+ - 发票:`crm_create_invoice` -> `/crmInvoice/add`,`crm_update_invoice` -> `/crmInvoice/update`
458
+ - 报价单:`crm_create_quotation` -> `/crmQuotation/add`,`crm_update_quotation` -> `/crmQuotation/update`
459
+
460
+ 这些工具支持两种传法。第一种是直接传 72CRM 原始保存 payload,适合前端或线上接口已经抓到完整结构的场景:
461
+
462
+ ```json
463
+ {
464
+ "body": {
465
+ "entity": {
466
+ "contractNum": "HT-001"
467
+ },
468
+ "field": [],
469
+ "product": [],
470
+ "examineFlowData": {
471
+ "label": 6,
472
+ "dataMap": {},
473
+ "flowDataList": []
474
+ }
475
+ },
476
+ "confirm": true
477
+ }
478
+ ```
479
+
480
+ 第二种是传 `fields/updates/fieldValues`,MCP 会先调用对应 `/field` 接口读取字段结构,再自动组装 `entity + field + product/contract + examineFlowData`:
481
+
482
+ ```json
483
+ {
484
+ "fields": {
485
+ "合同编号": "HT-001",
486
+ "合同金额": 1000,
487
+ "产品": {
488
+ "product": [
489
+ {
490
+ "productId": 10,
491
+ "name": [{ "name": "云服务" }],
492
+ "salesPrice": "288.5",
493
+ "num": 2,
494
+ "discount": "90"
495
+ }
496
+ ],
497
+ "totalPrice": "577",
498
+ "discountRate": "90"
499
+ }
500
+ },
501
+ "examineFlowData": {
502
+ "label": 6,
503
+ "dataMap": {},
504
+ "flowDataList": []
505
+ },
506
+ "confirm": true
507
+ }
508
+ ```
509
+
510
+ 合同、回款、发票、报价单通常受审批流配置影响。MCP 不会伪造审批流;如果没有传 `examineFlowData`,预览和写入结果会带 `approvalNotice` 提醒。若只想保存草稿,可传 `draft=true`,MCP 会补 `entity.checkStatus=5`。所有写入仍必须传 `confirm=true`。
511
+
512
+ ### 通讯录
513
+
514
+ 通讯录列表固定调用 `/adminUser/queryListName`,支持分页、搜索、部门、关注状态、首字母和首字母排序:
515
+
516
+ ```json
517
+ {
518
+ "page": 1,
519
+ "limit": 20,
520
+ "keyword": "张三",
521
+ "deptId": 8,
522
+ "status": 1,
523
+ "acronym": "Z",
524
+ "initial": 1
525
+ }
526
+ ```
527
+
528
+ 联系人详情固定调用 `/adminUser/queryUserInfo`:
529
+
530
+ ```json
531
+ {
532
+ "userId": 1001
533
+ }
534
+ ```
535
+
536
+ 组织和部门相关只读工具:
537
+
538
+ - `crm_list_address_book_departments` -> `/adminDept/queryDeptTree`
539
+ - `crm_list_address_book_auth_departments` -> `/adminDept/queryDeptByAuth`
540
+ - `crm_list_address_book_dept_user_ids` -> `/adminUser/queryUserByDeptIds`
541
+ - `crm_list_address_book_dept_users` -> `/adminUser/queryListByDeptIds`
542
+ - `crm_list_address_book_auth_users` -> `/adminUser/queryAuthUserList`
543
+ - `crm_get_address_book_user_dept_role_info` -> `/adminUser/queryUserDeptOrRoleInfo`
544
+ - `crm_get_address_book_organization` -> `/adminUser/queryOrganizationInfo`
545
+ - `crm_get_address_book_user_count` -> `/adminUser/queryUserNumInfo`
546
+
547
+ 按部门查询简要用户:
548
+
549
+ ```json
550
+ {
551
+ "deptIds": [8, 9]
552
+ }
553
+ ```
554
+
555
+ 按用户、部门、角色批量查询聚合信息:
556
+
557
+ ```json
558
+ {
559
+ "userIds": [1001],
560
+ "deptIds": [8],
561
+ "roleIds": [2]
562
+ }
563
+ ```
564
+
565
+ 关注状态切换固定调用 `/adminUser/attention`,`userId` 按 72CRM 后端要求走查询参数,必须传 `confirm=true` 才会写入:
566
+
567
+ ```json
568
+ {
569
+ "userId": 1001,
570
+ "confirm": true
571
+ }
572
+ ```
573
+
574
+ ### 办公审批
575
+
576
+ 审批类型固定调用 `/examines/queryPartList`,默认按 OA 审批传 `label=0`、`pageType=0`;审批分组固定调用 `/examineSuperExamines/queryExamineGroup`,默认 `groupType=0`。
577
+
578
+ 审批列表统一使用 `crm_list_oa_examines`,MCP 会按 `listType` 和 `tab` 映射到新版前端接口:
579
+
580
+ ```json
581
+ {
582
+ "listType": "upcoming",
583
+ "tab": "todo",
584
+ "page": 1,
585
+ "limit": 15,
586
+ "search": "报销"
587
+ }
588
+ ```
589
+
590
+ 常用映射包括:`upcoming/todo` -> `/examineSuperExamine/todo/me`,`upcoming/copy` -> `/examineSuperExamine/copy/me`,`track/me|do|copy`,`archive/me|audit|follow|tovoid|copy`,`draft`,`all`。也保留旧版 `legacyWaiting` -> `/examineWaiting/queryOaExamineList` 和 `legacyRecord` -> `/examineRecord/queryExamineRecordList`。
591
+
592
+ 审批详情固定调用 `/oaExamine/queryOaExamineInfo/{examineId}`。字段查询支持三种模式:传 `categoryId` 时默认调用 `/oaExamineField/queryField/{categoryId}` 获取新建审批自定义字段;传 `categoryId` 且 `mode=list` 时调用 `/oaExamineField/queryFieldList/{categoryId}`;传 `examineId` 或 `id` 时调用 `/oaExamine/getField` 获取详情字段。审批流转日志固定调用 `/examineRecord/queryExamineRecordLog`。
593
+
594
+ 新增审批、保存草稿、审批处理分别调用 `/oaExamine/setOaExamine`、`/oaExamine/setOaExamineDraft`、`/examineRecord/auditExamine`,批量审批调用 `/examineRecord/batchAuditExamine`。这些写操作都必须传 `confirm=true` 才会请求 72CRM;未传时只返回预览。
595
+
596
+ 新建审批支持两种传法。第一种是直接传 72CRM 原始 payload;第二种是传 `categoryId + fields/updates/fieldValues`,MCP 会先读取自定义字段结构,再自动组装为 `oaExamine + oaExamineRelation + field + oaExamineTravelList`:
597
+
598
+ ```json
599
+ {
600
+ "categoryId": 7,
601
+ "batchId": "可选附件批次ID",
602
+ "fields": {
603
+ "审批内容": "客户拜访报销",
604
+ "金额": 128.5,
605
+ "申请人": [{ "userId": 9 }]
606
+ },
607
+ "customerIds": [1001],
608
+ "confirm": true
609
+ }
610
+ ```
611
+
612
+ 系统字段会进入 `oaExamine`,自定义字段会进入 `field`;人员、部门、复选、分类、附件 batchId、明细表、出差/报销事项会按前端提交规则做转换。传 `strictRequired=true` 时会按字段元数据检查必填字段。
613
+
614
+ ### 日历日程
615
+
616
+ 日程列表固定调用 `/oaEvent/queryList`,详情固定调用 `/oaEvent/queryById`。列表查询的 `startTime`、`endTime` 按 72CRM 接口使用毫秒时间戳:
617
+
618
+ ```json
619
+ {
620
+ "startTime": 1782470400000,
621
+ "endTime": 1782556799999,
622
+ "typeIds": [1, 2],
623
+ "userId": 9
624
+ }
625
+ ```
626
+
627
+ 新增和修改日程分别调用 `/oaEvent/save`、`/oaEvent/update`,同样必须传 `confirm=true` 才会写入。可以直接传 72CRM 的 `SetEventBO` 结构:
628
+
629
+ ```json
630
+ {
631
+ "event": {
632
+ "eventId": 12,
633
+ "title": "客户回访",
634
+ "typeId": 3,
635
+ "startTime": "2026-06-26 10:00:00",
636
+ "endTime": "2026-06-26 11:00:00",
637
+ "ownerUserIds": "9",
638
+ "repetitionType": 1,
639
+ "endType": 1
640
+ },
641
+ "relation": {
642
+ "customerIds": "1001"
643
+ },
644
+ "notice": [
645
+ {
646
+ "type": 1,
647
+ "value": 15
648
+ }
649
+ ],
650
+ "confirm": true
651
+ }
652
+ ```
653
+
654
+ 也可以把 `title`、`typeId`、`startTime`、`endTime`、`ownerUserIds`、`customerIds`、`notices` 等字段放在顶层,MCP 会组装成 `SetEventBO`。删除日程、状态更新、单独增删关联仍不开放。
655
+
656
+ ### OA 公告
657
+
658
+ 公告列表和详情分别固定调用 `/oaAnnouncement/queryList`、`/oaAnnouncement/queryById/{announcementId}`:
659
+
660
+ ```json
661
+ {
662
+ "page": 1,
663
+ "limit": 20,
664
+ "type": 1
665
+ }
666
+ ```
667
+
668
+ 新增、编辑、删除和标记已读分别调用 `/oaAnnouncement/addAnnouncement`、`/oaAnnouncement/setAnnouncement`、`/oaAnnouncement/delete/{announcementId}`、`/oaAnnouncement/readAnnouncement`。写入类操作必须传 `confirm=true`;未确认时只返回目标地址和请求体预览。`deptIds`、`ownerUserIds`、`readUserIds` 支持传数组,MCP 会转成 72CRM 接口常用的逗号字符串。
669
+
670
+ ```json
671
+ {
672
+ "title": "公告标题",
673
+ "content": "公告内容",
674
+ "ownerUserIds": [9, 10],
675
+ "confirm": true
676
+ }
677
+ ```
678
+
679
+ ### OA 日志
680
+
681
+ 日志列表、详情、详情页字段、模板、模板字段、欢迎语、公告栏、完成统计、已完成/未完成记录分别固定调用:
682
+
683
+ - `/oaLog/queryList`
684
+ - `/oaLog/queryById`
685
+ - `/oaLog/information/{logId}`
686
+ - `/oaLogTemplate/queryPartList`
687
+ - `/oaLogTemplateField/field` 或 `/oaLogTemplateField/field/{logId}`
688
+ - `/oaLog/getLogWelcomeSpeech`
689
+ - `/oaLog/queryLogBulletin`
690
+ - `/oaLog/queryCompleteStats`
691
+ - `/oaLog/queryCompleteOaLogList`
692
+ - `/oaLog/queryIncompleteOaLogList`
693
+
694
+ 新增和编辑日志固定调用 `/oaLog/addOrUpdate`。可以直接传 `body` 原始 payload,也可以传 `categoryId + fields/updates/fieldValues`,MCP 会先读取日志模板字段并组装系统字段和自定义字段:
695
+
696
+ ```json
697
+ {
698
+ "categoryId": 7,
699
+ "title": "日报",
700
+ "sendUserIds": [9],
701
+ "fields": {
702
+ "日志内容": "今天完成客户回访",
703
+ "明日工作": "继续跟进报价",
704
+ "工时": 8
705
+ },
706
+ "confirm": true
707
+ }
708
+ ```
709
+
710
+ 删除日志和关注/取消关注分别调用 `/oaLog/deleteById`、`/oaLog/favourOrCancel`,都必须传 `confirm=true`。导出、打印和附件流下载仍不代理。
711
+
712
+ ### OA 任务
713
+
714
+ OA 任务列表固定调用 `/oaTask/queryTaskList`,支持 72CRM 的 `OaTaskListBO` 常用筛选字段:
715
+
716
+ ```json
717
+ {
718
+ "page": 1,
719
+ "limit": 20,
720
+ "type": 1,
721
+ "status": 1,
722
+ "priority": 3,
723
+ "keyword": "客户回访",
724
+ "mainUserIds": [9, 10]
725
+ }
726
+ ```
727
+
728
+ 关联业务任务固定调用 `/oaTask/queryTypeTaskList`:
729
+
730
+ ```json
731
+ {
732
+ "type": 2,
733
+ "typeId": 1001
734
+ }
735
+ ```
736
+
737
+ 新增主任务固定调用 `/workTask/saveWorkTask`,必须传 `confirm=true` 才会写入。可以直接传 `task`,也可以使用顶层字段:
738
+
739
+ ```json
740
+ {
741
+ "name": "客户回访",
742
+ "description": "确认续费计划",
743
+ "mainUserId": 9,
744
+ "ownerUserId": [9, 10],
745
+ "startTime": "2026-06-27",
746
+ "stopTime": "2026-06-28",
747
+ "priority": 3,
748
+ "labelId": [1, 2],
749
+ "customerIds": [1001],
750
+ "confirm": true
751
+ }
752
+ ```
753
+
754
+ 更新主任务字段固定映射到 72CRM 的独立接口,必须传 `confirm=true` 才会写入:
755
+
756
+ ```json
757
+ {
758
+ "taskId": 12,
759
+ "updates": {
760
+ "name": "客户回访-已更新",
761
+ "description": "带上报价单",
762
+ "mainUserId": 9,
763
+ "ownerUserId": [9, 10],
764
+ "startTime": "2026-06-27",
765
+ "stopTime": "2026-06-28",
766
+ "labelId": [1, 2],
767
+ "priority": 3,
768
+ "status": 5
769
+ },
770
+ "confirm": true
771
+ }
772
+ ```
773
+
774
+ 其中标题、描述、负责人、参与人、时间、标签、优先级、状态会分别调用 `/workTask/setWorkTaskTitle`、`/workTask/setWorkTaskDescription`、`/workTask/setWorkTaskMainUser`、`/workTask/setWorkTaskOwnerUser`、`/workTask/setWorkTaskTime`、`/workTask/setWorkTaskLabel`、`/workTask/setWorkTaskPriority`、`/workTask/setWorkTaskStatus`。删除任务、导出、子任务删除、删除参与人、删除标签暂不开放。
775
+
776
+ ### 人力资源 HRM
777
+
778
+ HRM 查询工具仍走固定只读接口;写入按“全部放开”开放到 HRM 域内固定路径。`crm_write_hrm` 只允许调用 `/hrm...` 开头的接口,支持直接传 `targetPath`,也支持传 `module + operation` 组合。未传 `confirm=true` 时只返回预览。
779
+
780
+ 员工列表固定调用 `/hrmEmployee/queryPageList`,`keyword`、`name`、`search` 会映射为 HRM 的 `employeeName`:
781
+
782
+ ```json
783
+ {
784
+ "page": 1,
785
+ "limit": 15,
786
+ "keyword": "张三",
787
+ "deptId": 8,
788
+ "status": 11
789
+ }
790
+ ```
791
+
792
+ 员工详情、字段表头、部门树、部门员工、岗位信息分别调用:
793
+
794
+ - `/hrmEmployee/queryById/{employeeId}`
795
+ - `/hrmEmployeeField/queryListHeads`
796
+ - `/hrmDept/queryTreeList`
797
+ - `/hrmDept/queryEmployeeByDeptId`
798
+ - `/hrmEmployeePost/postInformation/{employeeId}`
799
+
800
+ 考勤月汇总固定调用 `/hrmAttendanceEmpMonthRecord/queryAttendanceEmpMonthRecordPageList`:
801
+
802
+ ```json
803
+ {
804
+ "page": 1,
805
+ "limit": 20,
806
+ "search": "张三",
807
+ "deptIds": [8],
808
+ "times": ["2026-06-01", "2026-06-30"],
809
+ "isFullAttendance": 1
810
+ }
811
+ ```
812
+
813
+ 每日打卡明细固定调用 `/hrmAttendanceClock/queryAttendanceDailyDetail`:
814
+
815
+ ```json
816
+ {
817
+ "employeeId": 100,
818
+ "date": "2026-06-29"
819
+ }
820
+ ```
821
+
822
+ 请假记录和请假类型分别调用 `/hrmEmployeeLeaveRecord/queryLeaveRecordPageList`、`/hrmEmployeeLeaveRecord/queryLeaveTypeList`:
823
+
824
+ ```json
825
+ {
826
+ "employeeId": 100,
827
+ "times": ["2026-06-01", "2026-06-30"],
828
+ "leaveTypes": ["年假"]
829
+ }
830
+ ```
831
+
832
+ HRM 写入示例:
833
+
834
+ ```json
835
+ {
836
+ "targetPath": "/hrmEmployee/addEmployee",
837
+ "body": {
838
+ "field": [
839
+ { "fieldName": "employeeName", "value": "张三" }
840
+ ]
841
+ },
842
+ "confirm": true
843
+ }
844
+ ```
845
+
846
+ 也可以用组合形式调用任意 HRM 域内接口:
847
+
848
+ ```json
849
+ {
850
+ "module": "hrmEmployeePost",
851
+ "operation": "updatePostInformation",
852
+ "body": {
853
+ "employeeId": 100,
854
+ "post": "研发工程师"
855
+ },
856
+ "confirm": true
857
+ }
858
+ ```
859
+
860
+ ### 独立财务 FM
861
+
862
+ FM 当前接入独立财务模块,不包含 JXC 财务单据。查询工具仍固定调用只读接口;写入可使用 `crm_write_finance` 调用 `/finance...` 开头的独立财务接口,凭证新增/编辑提供了便捷工具。
863
+
864
+ 凭证列表、详情和汇总分别固定调用 `/financeCertificate/queryPageList`、`/financeCertificate/queryById`、`/financeCertificate/summary`:
865
+
866
+ ```json
867
+ {
868
+ "page": 1,
869
+ "limit": 20,
870
+ "accountId": 3,
871
+ "keyword": "付货款",
872
+ "certificateTime": ["2026-06-01", "2026-06-30"]
873
+ }
874
+ ```
875
+
876
+ 账簿查询使用 `crm_query_finance_ledger`,`ledger` 支持:
877
+
878
+ - `detail`: `/financeCertificate/queryDetailAccount`
879
+ - `general`: `/financeCertificate/queryGeneralLedger`
880
+ - `balance`: `/financeCertificate/queryDetailBalanceAccount`
881
+ - `multiColumn`: `/financeCertificate/queryDiversification`
882
+ - `itemsDetail`: `/financeCertificate/queryItemsDetailAccount`
883
+ - `itemsBalance`: `/financeCertificate/queryItemsDetailBalanceAccount`
884
+ - `amountDetail`: `/financeCertificate/queryAmountDetailAccount`
885
+ - `amountGeneral`: `/financeCertificate/queryAmountDetailUpAccount`
886
+
887
+ 财务报表使用 `crm_query_finance_report`,`report` 支持:
888
+
889
+ - `balanceSheet`: `/financeReport/balanceSheetReport`
890
+ - `incomeStatement`: `/financeReport/incomeStatementReport`
891
+ - `cashFlow`: `/financeReport/cashFlowStatementReport`
892
+
893
+ 传 `checkBalance=true` 时会调用对应报表的 `/balanceCheck` 接口。科目、币别、凭证字和仪表盘分别使用 `/financeSubject/list`、`/financeCurrency/queryAllList` 或 `/financeCurrency/queryListByAccountId`、`/financeVoucher/queryList`、`/financeDashboard/*` 的固定白名单查询。
894
+
895
+ 凭证新增和编辑:
896
+
897
+ ```json
898
+ {
899
+ "body": {
900
+ "accountId": 3,
901
+ "certificateTime": "2026-06-30",
902
+ "certificateItems": []
903
+ },
904
+ "confirm": true
905
+ }
906
+ ```
907
+
908
+ `crm_create_finance_voucher` 固定调用 `/financeCertificate/add`,`crm_update_finance_voucher` 固定调用 `/financeCertificate/update`,编辑时必须提供 `certificateId` 或 `id`:
909
+
910
+ ```json
911
+ {
912
+ "certificateId": 77,
913
+ "body": {
914
+ "accountId": 3,
915
+ "remark": "updated"
916
+ },
917
+ "confirm": true
918
+ }
919
+ ```
920
+
921
+ 其他 FM 写接口使用域级写入工具:
922
+
923
+ ```json
924
+ {
925
+ "targetPath": "/financeDigest/add",
926
+ "body": {
927
+ "accountId": 3,
928
+ "digestContent": "付货款"
929
+ },
930
+ "confirm": true
931
+ }
932
+ ```
933
+
934
+ ### 进销存 JXC
935
+
936
+ JXC 查询保留产品、供应商、仓库、库存和出入库明细的固定接口。写入按“全部放开”开放到 JXC 域内固定路径:产品、供应商、仓库提供便捷新增/编辑工具,其他 JXC 单据、资金、库存、设置类写接口可使用 `crm_write_jxc`。
937
+
938
+ 主数据模块可以先用 `crm_list_jxc_modules` 查看固定白名单,再用统一查询工具访问:
939
+
940
+ ```json
941
+ {
942
+ "module": "product",
943
+ "page": 1,
944
+ "limit": 20,
945
+ "keyword": "电机",
946
+ "warehouseId": 8
947
+ }
948
+ ```
949
+
950
+ `crm_search_jxc_records` 会按模块固定调用 `/jxcProduct/queryPageList`、`/jxcSupplier/queryPageList` 或 `/jxcWarehouse/queryPageList`。详情、详情页字段、字段结构、附件元数据分别调用:
951
+
952
+ - `/jxcProduct|jxcSupplier|jxcWarehouse/queryById/{id}`
953
+ - `/jxcProduct|jxcSupplier|jxcWarehouse/information/{id}`
954
+ - `/jxcProduct|jxcSupplier|jxcWarehouse/field`
955
+ - `/jxcProduct|jxcSupplier|jxcWarehouse/queryFileList`
956
+
957
+ 库存列表固定调用 `/jxcWarehouseProduct/queryPageList`:
958
+
959
+ ```json
960
+ {
961
+ "page": 1,
962
+ "limit": 20,
963
+ "keyword": "电机",
964
+ "productCode": "P-100",
965
+ "warehouseId": 8,
966
+ "stock": "1"
967
+ }
968
+ ```
969
+
970
+ 产品库存、出入库明细、仓库产品库存数量和仓库名称分别调用:
971
+
972
+ - `/jxcProduct/queryProductInventory/{productId}`
973
+ - `/jxcDetailed/queryPageList`
974
+ - `/jxcWarehouse/queryProductWarehouseNumBatch`
975
+ - `/jxcWarehouse/queryWarehouseNameByIds`
976
+
977
+ 产品、供应商、仓库主数据新增/编辑:
978
+
979
+ ```json
980
+ {
981
+ "module": "product",
982
+ "entity": {
983
+ "name": "电机"
984
+ },
985
+ "field": [],
986
+ "confirm": true
987
+ }
988
+ ```
989
+
990
+ ```json
991
+ {
992
+ "module": "supplier",
993
+ "id": 88,
994
+ "entity": {
995
+ "name": "新供应商"
996
+ },
997
+ "field": [],
998
+ "confirm": true
999
+ }
1000
+ ```
1001
+
1002
+ 其他 JXC 写接口示例:
1003
+
1004
+ ```json
1005
+ {
1006
+ "module": "jxcPurchase",
1007
+ "operation": "add",
1008
+ "body": {
1009
+ "entity": {
1010
+ "orderNo": "PO-001"
1011
+ },
1012
+ "field": []
1013
+ },
1014
+ "confirm": true
1015
+ }
1016
+ ```
1017
+
1018
+ ## 工单
1019
+
1020
+ 工单工具用于兼容 PHP 工单能力,同时保持标准 MCP 的固定接口和确认写入边界。
1021
+
1022
+ - `workorder_search_records`:普通工单、工单池和线下工单分页查询。`scope=pool` 时固定调用 `/wkoWorkorder/queryPageList` 并传 `isPool=1`,`scope=offline` 时调用 `/wkoOfflineWorkorder/queryPageList`。
1023
+ - `workorder_get_record`:查询普通工单或线下工单详情,并同时读取详情字段 `/information/{id}`。
1024
+ - `workorder_get_schema`:查询普通工单或线下工单字段结构,可传 `id` 获取编辑字段。
1025
+ - `workorder_preview_write`:只生成新建或更新请求体,不调用写接口。
1026
+ - `workorder_create_record`:显式 `confirm=true` 后调用 `/wkoWorkorder/add` 或 `/wkoOfflineWorkorder/add`,写入后自动回读。
1027
+ - `workorder_update_record`:显式 `confirm=true` 后调用 `/wkoWorkorder/update` 或 `/wkoOfflineWorkorder/update`,写入后自动回读。
1028
+
1029
+ 普通工单新建示例:
1030
+
1031
+ ```json
1032
+ {
1033
+ "entity": {
1034
+ "name": "测试工单"
1035
+ },
1036
+ "field": [],
1037
+ "confirm": true
1038
+ }
1039
+ ```
1040
+
1041
+ 线下工单新建示例:
1042
+
1043
+ ```json
1044
+ {
1045
+ "scope": "offline",
1046
+ "body": {
1047
+ "name": "线下维修工单"
1048
+ },
1049
+ "confirm": true
1050
+ }
1051
+ ```
1052
+
217
1053
  ## 安全边界
218
1054
 
219
- 以下操作前期全部拒绝:删除、转移负责人、公海流转、导入导出、审批/状态流转、字段配置修改、附件上传。
1055
+ HRM、JXC、FM 和工单写入已按要求开放到域内固定路径,但仍保留这些硬边界:
1056
+
1057
+ - 必须传 `confirm=true` 才会请求 72CRM;否则只返回预览。
1058
+ - `crm_write_hrm` 只能调用 `/hrm...`,`crm_write_jxc` 只能调用 `/jxc...`,`crm_write_finance` 只能调用 `/finance...`。
1059
+ - 工单工具只调用 `/wkoWorkorder...` 与 `/wkoOfflineWorkorder...` 固定路径,不开放任意工单路径透传。
1060
+ - 不允许 `targetPath` 使用完整 URL、跨域路径、`..`、查询串或片段。
1061
+ - 不代理文件流下载,不处理 multipart 文件上传;附件上传仍不支持。
1062
+ - 这些写入会真实修改 HRM/JXC/FM/工单业务数据,调用前请先用 `confirm=false` 看预览体。