@yanhaidao/wecom 2.4.120 → 2.5.110
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 +4 -5
- package/dist/index.js +68 -0
- package/dist/src/accounts.js +20 -0
- package/dist/src/agent/handler.js +895 -0
- package/dist/src/agent/index.js +5 -0
- package/dist/src/app/account-runtime.js +216 -0
- package/dist/src/app/bootstrap.js +19 -0
- package/dist/src/app/index.js +118 -0
- package/dist/src/capability/agent/delivery-service.js +63 -0
- package/dist/src/capability/agent/fallback-policy.js +6 -0
- package/dist/src/capability/agent/ingress-service.js +33 -0
- package/dist/src/capability/agent/upstream-delivery-service.js +71 -0
- package/dist/src/capability/bot/dispatch-config.js +45 -0
- package/dist/src/capability/bot/fallback-delivery.js +147 -0
- package/dist/src/capability/bot/local-path-delivery.js +178 -0
- package/dist/src/capability/bot/sandbox-media.js +138 -0
- package/dist/src/capability/bot/service.js +49 -0
- package/dist/src/capability/bot/stream-delivery.js +321 -0
- package/dist/src/capability/bot/stream-finalizer.js +81 -0
- package/dist/src/capability/bot/stream-orchestrator.js +318 -0
- package/dist/src/capability/bot/types.js +1 -0
- package/{src/capability/calendar/client.ts → dist/src/capability/calendar/client.js} +118 -241
- package/{src/capability/calendar/schema.ts → dist/src/capability/calendar/schema.js} +0 -38
- package/dist/src/capability/calendar/tool.js +365 -0
- package/dist/src/capability/calendar/types.js +12 -0
- package/{src/capability/doc/client.ts → dist/src/capability/doc/client.js} +370 -605
- package/{src/capability/doc/schema.ts → dist/src/capability/doc/schema.js} +345 -394
- package/dist/src/capability/doc/tool.js +1556 -0
- package/dist/src/capability/doc/types.js +113 -0
- package/dist/src/capability/mcp/index.js +3 -0
- package/dist/src/capability/mcp/schema.js +102 -0
- package/dist/src/capability/mcp/tool.js +146 -0
- package/dist/src/capability/mcp/transport.js +293 -0
- package/dist/src/channel.js +224 -0
- package/dist/src/config/accounts.js +236 -0
- package/dist/src/config/derived-paths.js +31 -0
- package/dist/src/config/index.js +7 -0
- package/dist/src/config/media.js +110 -0
- package/dist/src/config/network.js +32 -0
- package/dist/src/config/routing.js +20 -0
- package/dist/src/config/runtime-config.js +25 -0
- package/dist/src/config/schema.js +4 -0
- package/{src/config-schema.ts → dist/src/config-schema.js} +1 -1
- package/dist/src/context-store.js +219 -0
- package/{src/crypto/aes.ts → dist/src/crypto/aes.js} +11 -28
- package/dist/src/crypto/index.js +9 -0
- package/{src/crypto/signature.ts → dist/src/crypto/signature.js} +3 -18
- package/{src/crypto/xml.ts → dist/src/crypto/xml.js} +3 -11
- package/dist/src/crypto.js +145 -0
- package/dist/src/domain/models.js +1 -0
- package/dist/src/domain/policies.js +32 -0
- package/{src/dynamic-agent.ts → dist/src/dynamic-agent.js} +36 -73
- package/dist/src/gateway-monitor.js +139 -0
- package/dist/src/http.js +114 -0
- package/{src/media.ts → dist/src/media.js} +21 -40
- package/dist/src/monitor/limits.js +7 -0
- package/dist/src/monitor/state.js +28 -0
- package/dist/src/monitor.js +84 -0
- package/dist/src/observability/audit-log.js +30 -0
- package/dist/src/observability/legacy-operational-event-store.js +22 -0
- package/dist/src/observability/raw-envelope-log.js +24 -0
- package/dist/src/observability/status-registry.js +9 -0
- package/dist/src/observability/transport-session-view.js +14 -0
- package/dist/src/onboarding.js +546 -0
- package/dist/src/outbound.js +557 -0
- package/dist/src/runtime/dispatcher.js +57 -0
- package/{src/runtime/index.ts → dist/src/runtime/index.js} +0 -1
- package/dist/src/runtime/outbound-intent.js +1 -0
- package/dist/src/runtime/reply-orchestrator.js +38 -0
- package/dist/src/runtime/routing-bridge.js +26 -0
- package/dist/src/runtime/session-manager.js +112 -0
- package/dist/src/runtime/source-registry.js +174 -0
- package/dist/src/runtime.js +1 -0
- package/dist/src/shared/command-auth.js +57 -0
- package/{src/shared/index.ts → dist/src/shared/index.js} +0 -1
- package/dist/src/shared/media-asset.js +65 -0
- package/dist/src/shared/media-service.js +59 -0
- package/dist/src/shared/media-types.js +1 -0
- package/{src/shared/xml-parser.ts → dist/src/shared/xml-parser.js} +72 -63
- package/dist/src/store/active-reply-store.js +41 -0
- package/dist/src/store/interfaces.js +1 -0
- package/dist/src/store/memory-store.js +33 -0
- package/dist/src/store/stream-batch-store.js +319 -0
- package/{src/target.ts → dist/src/target.js} +15 -48
- package/dist/src/transport/agent-api/client.js +168 -0
- package/dist/src/transport/agent-api/core.js +337 -0
- package/dist/src/transport/agent-api/delivery.js +28 -0
- package/dist/src/transport/agent-api/media-upload.js +4 -0
- package/dist/src/transport/agent-api/reply.js +24 -0
- package/dist/src/transport/agent-api/upstream-delivery.js +30 -0
- package/dist/src/transport/agent-api/upstream-media-upload.js +46 -0
- package/dist/src/transport/agent-api/upstream-reply.js +26 -0
- package/dist/src/transport/agent-callback/http-handler.js +30 -0
- package/dist/src/transport/agent-callback/inbound.js +4 -0
- package/dist/src/transport/agent-callback/reply.js +8 -0
- package/dist/src/transport/agent-callback/request-handler.js +189 -0
- package/dist/src/transport/agent-callback/session.js +15 -0
- package/dist/src/transport/bot-webhook/active-reply.js +27 -0
- package/dist/src/transport/bot-webhook/http-handler.js +31 -0
- package/dist/src/transport/bot-webhook/inbound-normalizer.js +496 -0
- package/dist/src/transport/bot-webhook/inbound.js +4 -0
- package/dist/src/transport/bot-webhook/message-shape.js +98 -0
- package/dist/src/transport/bot-webhook/protocol.js +124 -0
- package/dist/src/transport/bot-webhook/reply.js +9 -0
- package/dist/src/transport/bot-webhook/request-handler.js +285 -0
- package/dist/src/transport/bot-webhook/session.js +15 -0
- package/dist/src/transport/bot-ws/inbound.js +147 -0
- package/dist/src/transport/bot-ws/media.js +236 -0
- package/dist/src/transport/bot-ws/reply.js +310 -0
- package/dist/src/transport/bot-ws/sdk-adapter.js +257 -0
- package/dist/src/transport/bot-ws/session.js +15 -0
- package/dist/src/transport/http/common.js +78 -0
- package/dist/src/transport/http/registry.js +71 -0
- package/dist/src/transport/http/request-handler.js +51 -0
- package/{src/transport/index.ts → dist/src/transport/index.js} +2 -10
- package/dist/src/types/account.js +1 -0
- package/dist/src/types/config.js +1 -0
- package/dist/src/types/constants.js +28 -0
- package/dist/src/types/events.js +1 -0
- package/dist/src/types/index.js +1 -0
- package/dist/src/types/legacy-stream.js +1 -0
- package/dist/src/types/message.js +5 -0
- package/dist/src/types/runtime-context.js +1 -0
- package/dist/src/types/runtime.js +1 -0
- package/dist/src/types.js +1 -0
- package/dist/src/upstream/index.js +111 -0
- package/dist/src/wecom_msg_adapter/markdown_adapter.js +280 -0
- package/openclaw.plugin.json +15 -0
- package/package.json +18 -1
- package/.github/workflows/release.yml +0 -143
- package/GOVERNANCE.md +0 -26
- package/MENU_EVENT_CONF.md +0 -500
- package/MENU_EVENT_PLAN.md +0 -440
- package/SKILLS_CAL.md +0 -895
- package/SKILLS_DOC.md +0 -2288
- package/UPSTREAM_CONFIG.md +0 -170
- package/UPSTREAM_PLAN.md +0 -175
- package/assets/01.bot-add.png +0 -0
- package/assets/01.bot-setp2.png +0 -0
- package/assets/01.image.jpg +0 -0
- package/assets/02.agent.add.png +0 -0
- package/assets/02.agent.api-set.png +0 -0
- package/assets/02.image.jpg +0 -0
- package/assets/03.agent.page.png +0 -0
- package/assets/03.bot.page.png +0 -0
- package/assets/link-me.jpg +0 -0
- package/assets/register.png +0 -0
- package/changelog/v2.2.28.md +0 -70
- package/changelog/v2.3.10.md +0 -17
- package/changelog/v2.3.11.md +0 -19
- package/changelog/v2.3.12.md +0 -25
- package/changelog/v2.3.13.md +0 -19
- package/changelog/v2.3.14.md +0 -48
- package/changelog/v2.3.15.md +0 -15
- package/changelog/v2.3.16.md +0 -11
- package/changelog/v2.3.18.md +0 -22
- package/changelog/v2.3.19.md +0 -73
- package/changelog/v2.3.2.md +0 -28
- package/changelog/v2.3.26.md +0 -21
- package/changelog/v2.3.27.md +0 -33
- package/changelog/v2.3.4.md +0 -20
- package/changelog/v2.3.9.md +0 -22
- package/changelog/v2.4.12.md +0 -37
- package/compat-single-account.md +0 -148
- package/index.test.ts +0 -38
- package/scripts/test-proxy.ts +0 -70
- package/scripts/wecom/README.md +0 -123
- package/scripts/wecom/menu-click-help.js +0 -59
- package/scripts/wecom/menu-click-help.py +0 -55
- package/src/accounts.ts +0 -34
- package/src/agent/api-client.upload.test.ts +0 -109
- package/src/agent/event-router.test.ts +0 -421
- package/src/agent/event-router.ts +0 -272
- package/src/agent/handler.event-filter.test.ts +0 -135
- package/src/agent/handler.ts +0 -1250
- package/src/agent/index.ts +0 -12
- package/src/agent/script-runner.ts +0 -186
- package/src/agent/test-fixtures/invalid-json-script.mjs +0 -1
- package/src/agent/test-fixtures/reply-event-script.mjs +0 -29
- package/src/agent/test-fixtures/reply-event-script.py +0 -17
- package/src/app/account-runtime.ts +0 -276
- package/src/app/bootstrap.ts +0 -29
- package/src/app/index.ts +0 -192
- package/src/capability/agent/delivery-service.ts +0 -87
- package/src/capability/agent/fallback-policy.ts +0 -13
- package/src/capability/agent/ingress-service.ts +0 -38
- package/src/capability/agent/upstream-delivery-service.ts +0 -96
- package/src/capability/bot/dispatch-config.ts +0 -47
- package/src/capability/bot/fallback-delivery.ts +0 -178
- package/src/capability/bot/local-path-delivery.ts +0 -215
- package/src/capability/bot/sandbox-media.test.ts +0 -221
- package/src/capability/bot/sandbox-media.ts +0 -176
- package/src/capability/bot/service.ts +0 -56
- package/src/capability/bot/stream-delivery.ts +0 -379
- package/src/capability/bot/stream-finalizer.ts +0 -120
- package/src/capability/bot/stream-orchestrator.ts +0 -371
- package/src/capability/bot/types.ts +0 -8
- package/src/capability/calendar/SKILLS_CHECKLIST.md +0 -251
- package/src/capability/calendar/tool.ts +0 -417
- package/src/capability/calendar/types.ts +0 -309
- package/src/capability/doc/tool.ts +0 -1629
- package/src/capability/doc/types.ts +0 -792
- package/src/capability/mcp/index.ts +0 -10
- package/src/capability/mcp/schema.ts +0 -107
- package/src/capability/mcp/tool.ts +0 -174
- package/src/capability/mcp/transport.ts +0 -394
- package/src/channel.config.test.ts +0 -180
- package/src/channel.lifecycle.test.ts +0 -255
- package/src/channel.meta.test.ts +0 -26
- package/src/channel.ts +0 -256
- package/src/config/accounts.resolve.test.ts +0 -75
- package/src/config/accounts.ts +0 -312
- package/src/config/derived-paths.test.ts +0 -111
- package/src/config/derived-paths.ts +0 -41
- package/src/config/index.ts +0 -22
- package/src/config/media.test.ts +0 -113
- package/src/config/media.ts +0 -139
- package/src/config/network.ts +0 -20
- package/src/config/routing.test.ts +0 -88
- package/src/config/routing.ts +0 -26
- package/src/config/runtime-config.ts +0 -46
- package/src/config/schema.ts +0 -144
- package/src/context-store.ts +0 -297
- package/src/crypto/index.ts +0 -24
- package/src/crypto.test.ts +0 -32
- package/src/crypto.ts +0 -176
- package/src/domain/models.ts +0 -7
- package/src/domain/policies.ts +0 -36
- package/src/dynamic-agent.account-scope.test.ts +0 -17
- package/src/gateway-monitor.ts +0 -181
- package/src/http.ts +0 -137
- package/src/media.test.ts +0 -82
- package/src/monitor/limits.ts +0 -7
- package/src/monitor/state.queue.test.ts +0 -185
- package/src/monitor/state.ts +0 -34
- package/src/monitor.active.test.ts +0 -245
- package/src/monitor.inbound-filter.test.ts +0 -63
- package/src/monitor.integration.test.ts +0 -208
- package/src/monitor.ts +0 -121
- package/src/monitor.webhook.test.ts +0 -774
- package/src/observability/audit-log.ts +0 -48
- package/src/observability/legacy-operational-event-store.ts +0 -36
- package/src/observability/raw-envelope-log.ts +0 -28
- package/src/observability/status-registry.ts +0 -13
- package/src/observability/transport-session-view.ts +0 -14
- package/src/onboarding.test.ts +0 -336
- package/src/onboarding.ts +0 -704
- package/src/outbound.test.ts +0 -1271
- package/src/outbound.ts +0 -746
- package/src/runtime/dispatcher.ts +0 -71
- package/src/runtime/outbound-intent.ts +0 -4
- package/src/runtime/reply-orchestrator.test.ts +0 -71
- package/src/runtime/reply-orchestrator.ts +0 -67
- package/src/runtime/routing-bridge.test.ts +0 -115
- package/src/runtime/routing-bridge.ts +0 -44
- package/src/runtime/session-manager.test.ts +0 -174
- package/src/runtime/session-manager.ts +0 -139
- package/src/runtime/source-registry.ts +0 -249
- package/src/runtime.ts +0 -14
- package/src/shared/command-auth.ts +0 -87
- package/src/shared/media-asset.ts +0 -78
- package/src/shared/media-service.test.ts +0 -111
- package/src/shared/media-service.ts +0 -84
- package/src/shared/media-types.ts +0 -5
- package/src/shared/xml-parser.test.ts +0 -50
- package/src/store/active-reply-store.ts +0 -42
- package/src/store/interfaces.ts +0 -11
- package/src/store/memory-store.ts +0 -43
- package/src/store/stream-batch-store.ts +0 -350
- package/src/transport/agent-api/client.ts +0 -277
- package/src/transport/agent-api/core.ts +0 -463
- package/src/transport/agent-api/delivery.ts +0 -41
- package/src/transport/agent-api/media-upload.ts +0 -11
- package/src/transport/agent-api/reply.ts +0 -39
- package/src/transport/agent-api/upstream-delivery.ts +0 -45
- package/src/transport/agent-api/upstream-media-upload.ts +0 -70
- package/src/transport/agent-api/upstream-reply.ts +0 -43
- package/src/transport/agent-callback/http-handler.ts +0 -47
- package/src/transport/agent-callback/inbound.ts +0 -5
- package/src/transport/agent-callback/reply.ts +0 -13
- package/src/transport/agent-callback/request-handler.ts +0 -244
- package/src/transport/agent-callback/session.ts +0 -23
- package/src/transport/bot-webhook/active-reply.ts +0 -39
- package/src/transport/bot-webhook/http-handler.ts +0 -48
- package/src/transport/bot-webhook/inbound-normalizer.ts +0 -371
- package/src/transport/bot-webhook/inbound.ts +0 -5
- package/src/transport/bot-webhook/message-shape.ts +0 -89
- package/src/transport/bot-webhook/protocol.ts +0 -148
- package/src/transport/bot-webhook/reply.ts +0 -15
- package/src/transport/bot-webhook/request-handler.ts +0 -394
- package/src/transport/bot-webhook/session.ts +0 -23
- package/src/transport/bot-ws/inbound.test.ts +0 -96
- package/src/transport/bot-ws/inbound.ts +0 -116
- package/src/transport/bot-ws/media.test.ts +0 -44
- package/src/transport/bot-ws/media.ts +0 -321
- package/src/transport/bot-ws/reply.test.ts +0 -450
- package/src/transport/bot-ws/reply.ts +0 -365
- package/src/transport/bot-ws/sdk-adapter.test.ts +0 -187
- package/src/transport/bot-ws/sdk-adapter.ts +0 -314
- package/src/transport/bot-ws/session.ts +0 -28
- package/src/transport/http/common.ts +0 -109
- package/src/transport/http/registry.ts +0 -92
- package/src/transport/http/request-handler.ts +0 -84
- package/src/types/account.ts +0 -72
- package/src/types/config.ts +0 -166
- package/src/types/constants.ts +0 -31
- package/src/types/events.ts +0 -21
- package/src/types/global.d.ts +0 -9
- package/src/types/index.ts +0 -17
- package/src/types/legacy-stream.ts +0 -50
- package/src/types/message.ts +0 -187
- package/src/types/runtime-context.ts +0 -28
- package/src/types/runtime.ts +0 -165
- package/src/types.ts +0 -41
- package/src/upstream/index.ts +0 -150
- package/src/upstream.test.ts +0 -84
- package/src/wecom_msg_adapter/markdown_adapter.ts +0 -331
- package/tsconfig.json +0 -22
- package/vitest.config.ts +0 -26
- /package/{src/capability/agent/index.ts → dist/src/capability/agent/index.js} +0 -0
- /package/{src/capability/bot/index.ts → dist/src/capability/bot/index.js} +0 -0
- /package/{src/capability/calendar/index.ts → dist/src/capability/calendar/index.js} +0 -0
- /package/{src/capability/index.ts → dist/src/capability/index.js} +0 -0
|
@@ -1,126 +1,103 @@
|
|
|
1
|
-
import type { ResolvedAgentAccount } from "../../types/index.js";
|
|
2
1
|
import { getAccessToken } from "../../transport/agent-api/core.js";
|
|
3
2
|
import { wecomFetch } from "../../http.js";
|
|
4
3
|
import { resolveWecomEgressProxyUrlFromNetwork } from "../../config/index.js";
|
|
5
4
|
import { LIMITS } from "../../types/constants.js";
|
|
6
|
-
|
|
7
|
-
BatchUpdateDocResponse,
|
|
8
|
-
GetDocContentResponse,
|
|
9
|
-
Node,
|
|
10
|
-
UpdateRequest
|
|
11
|
-
} from "./types.js";
|
|
12
|
-
|
|
13
|
-
function readString(value: unknown): string {
|
|
5
|
+
function readString(value) {
|
|
14
6
|
const trimmed = String(value ?? "").trim();
|
|
15
7
|
return trimmed || "";
|
|
16
8
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (docType === 4 || docType === "4")
|
|
21
|
-
|
|
9
|
+
function normalizeDocType(docType) {
|
|
10
|
+
if (docType === 3 || docType === "3")
|
|
11
|
+
return 3;
|
|
12
|
+
if (docType === 4 || docType === "4")
|
|
13
|
+
return 4;
|
|
14
|
+
if (docType === 10 || docType === "10" || docType === 5 || docType === "5")
|
|
15
|
+
return 10;
|
|
22
16
|
const normalized = readString(docType).toLowerCase();
|
|
23
|
-
if (!normalized || normalized === "doc")
|
|
24
|
-
|
|
25
|
-
if (normalized === "
|
|
17
|
+
if (!normalized || normalized === "doc")
|
|
18
|
+
return 3;
|
|
19
|
+
if (normalized === "spreadsheet" || normalized === "sheet" || normalized === "table")
|
|
20
|
+
return 4;
|
|
21
|
+
if (normalized === "smart_table" || normalized === "smarttable")
|
|
22
|
+
return 10;
|
|
26
23
|
throw new Error(`Unsupported WeCom docType: ${String(docType)}`);
|
|
27
24
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (docType === 4)
|
|
25
|
+
function mapDocTypeLabel(docType) {
|
|
26
|
+
if (docType === 10)
|
|
27
|
+
return "smart_table";
|
|
28
|
+
if (docType === 4)
|
|
29
|
+
return "spreadsheet";
|
|
32
30
|
return "doc";
|
|
33
31
|
}
|
|
34
|
-
|
|
35
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
32
|
+
function isRecord(value) {
|
|
36
33
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
37
34
|
}
|
|
38
|
-
|
|
39
|
-
function readObject(value: unknown): Record<string, unknown> {
|
|
35
|
+
function readObject(value) {
|
|
40
36
|
return isRecord(value) ? value : {};
|
|
41
37
|
}
|
|
42
|
-
|
|
43
|
-
function readArray(value: unknown): unknown[] {
|
|
38
|
+
function readArray(value) {
|
|
44
39
|
return Array.isArray(value) ? value : [];
|
|
45
40
|
}
|
|
46
|
-
|
|
47
|
-
export interface DocMemberEntry {
|
|
48
|
-
userid?: string;
|
|
49
|
-
partyid?: string;
|
|
50
|
-
tagid?: string;
|
|
51
|
-
/**
|
|
52
|
-
* 权限位:1-查看,2-编辑,7-管理
|
|
53
|
-
* 只有“智能表格”才支持读写权限(auth=2)?
|
|
54
|
-
* 实际上企微文档现在也支持设置协作者权限了。
|
|
55
|
-
*/
|
|
56
|
-
auth?: number;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function normalizeDocMemberEntry(value: unknown): DocMemberEntry | null {
|
|
41
|
+
function normalizeDocMemberEntry(value) {
|
|
60
42
|
if (typeof value === "string" || typeof value === "number") {
|
|
61
43
|
const userid = readString(value);
|
|
62
44
|
return userid ? { userid } : null;
|
|
63
45
|
}
|
|
64
|
-
if (!isRecord(value))
|
|
65
|
-
|
|
46
|
+
if (!isRecord(value))
|
|
47
|
+
return null;
|
|
48
|
+
const entry = { ...value };
|
|
66
49
|
if (!readString(entry.userid) && readString(value.userId)) {
|
|
67
50
|
entry.userid = readString(value.userId);
|
|
68
51
|
}
|
|
69
52
|
if (!readString(entry.userid) && !readString(entry.partyid) && !readString(entry.tagid)) {
|
|
70
53
|
return null;
|
|
71
54
|
}
|
|
72
|
-
if (readString(entry.userid))
|
|
73
|
-
|
|
74
|
-
if (readString(entry.
|
|
75
|
-
|
|
55
|
+
if (readString(entry.userid))
|
|
56
|
+
entry.userid = readString(entry.userid);
|
|
57
|
+
if (readString(entry.partyid))
|
|
58
|
+
entry.partyid = readString(entry.partyid);
|
|
59
|
+
if (readString(entry.tagid))
|
|
60
|
+
entry.tagid = readString(entry.tagid);
|
|
61
|
+
if (entry.auth !== undefined)
|
|
62
|
+
entry.auth = Number(entry.auth);
|
|
76
63
|
return entry;
|
|
77
64
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return readArray(values).map(normalizeDocMemberEntry).filter((v): v is DocMemberEntry => v !== null);
|
|
65
|
+
function normalizeDocMemberEntryList(values) {
|
|
66
|
+
return readArray(values).map(normalizeDocMemberEntry).filter((v) => v !== null);
|
|
81
67
|
}
|
|
82
|
-
|
|
83
|
-
function buildDocMemberAuthRequest(params: {
|
|
84
|
-
docId: string;
|
|
85
|
-
viewers?: unknown;
|
|
86
|
-
collaborators?: unknown;
|
|
87
|
-
removeViewers?: unknown;
|
|
88
|
-
removeCollaborators?: unknown;
|
|
89
|
-
authLevel?: number; // Default auth level for new members if not specified in entry
|
|
90
|
-
}): Record<string, unknown> {
|
|
68
|
+
function buildDocMemberAuthRequest(params) {
|
|
91
69
|
const { docId, viewers, collaborators, removeViewers, removeCollaborators, authLevel } = params;
|
|
92
|
-
const payload
|
|
70
|
+
const payload = {
|
|
93
71
|
docid: readString(docId),
|
|
94
72
|
};
|
|
95
|
-
if (!payload.docid)
|
|
96
|
-
|
|
73
|
+
if (!payload.docid)
|
|
74
|
+
throw new Error("docId required");
|
|
97
75
|
const normalizedViewers = normalizeDocMemberEntryList(viewers).map(v => ({ ...v, auth: v.auth ?? authLevel ?? 1 }));
|
|
98
76
|
const normalizedCollaborators = normalizeDocMemberEntryList(collaborators).map(v => ({ ...v, auth: v.auth ?? authLevel ?? 2 }));
|
|
99
77
|
const normalizedRemovedViewers = normalizeDocMemberEntryList(removeViewers);
|
|
100
78
|
const normalizedRemovedCollaborators = normalizeDocMemberEntryList(removeCollaborators);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (normalizedCollaborators.length > 0)
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
if (
|
|
108
|
-
|
|
79
|
+
if (normalizedViewers.length > 0)
|
|
80
|
+
payload.update_file_member_list = normalizedViewers;
|
|
81
|
+
if (normalizedCollaborators.length > 0)
|
|
82
|
+
payload.update_co_auth_list = normalizedCollaborators;
|
|
83
|
+
if (normalizedRemovedViewers.length > 0)
|
|
84
|
+
payload.del_file_member_list = normalizedRemovedViewers;
|
|
85
|
+
if (normalizedRemovedCollaborators.length > 0)
|
|
86
|
+
payload.del_co_auth_list = normalizedRemovedCollaborators;
|
|
87
|
+
if (!payload.update_doc_member_list &&
|
|
109
88
|
!payload.update_co_auth_list &&
|
|
110
89
|
!payload.del_doc_member_list &&
|
|
111
|
-
!payload.del_co_auth_list
|
|
112
|
-
) {
|
|
90
|
+
!payload.del_co_auth_list) {
|
|
113
91
|
throw new Error("at least one viewer/collaborator change is required");
|
|
114
92
|
}
|
|
115
|
-
|
|
116
93
|
return payload;
|
|
117
94
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
let payload: any = null;
|
|
95
|
+
async function parseJsonResponse(res, actionLabel) {
|
|
96
|
+
let payload = null;
|
|
121
97
|
try {
|
|
122
98
|
payload = await res.json();
|
|
123
|
-
}
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
124
101
|
if (!res.ok) {
|
|
125
102
|
throw new Error(`WeCom ${actionLabel} failed: HTTP ${res.status}`);
|
|
126
103
|
}
|
|
@@ -135,34 +112,22 @@ async function parseJsonResponse(res: Response, actionLabel: string): Promise<an
|
|
|
135
112
|
if (Array.isArray(payload)) {
|
|
136
113
|
const failedItem = payload.find((item) => Number(item?.errcode ?? 0) !== 0);
|
|
137
114
|
if (failedItem) {
|
|
138
|
-
throw new Error(
|
|
139
|
-
`WeCom ${actionLabel} failed: ${String(failedItem?.errmsg || "unknown error")} (errcode ${String(failedItem?.errcode)})`,
|
|
140
|
-
);
|
|
115
|
+
throw new Error(`WeCom ${actionLabel} failed: ${String(failedItem?.errmsg || "unknown error")} (errcode ${String(failedItem?.errcode)})`);
|
|
141
116
|
}
|
|
142
117
|
return payload;
|
|
143
118
|
}
|
|
144
119
|
if (Number(payload.errcode ?? 0) !== 0) {
|
|
145
|
-
throw new Error(
|
|
146
|
-
`WeCom ${actionLabel} failed: ${String(payload.errmsg || "unknown error")} (errcode ${String(payload.errcode)})`,
|
|
147
|
-
);
|
|
120
|
+
throw new Error(`WeCom ${actionLabel} failed: ${String(payload.errmsg || "unknown error")} (errcode ${String(payload.errcode)})`);
|
|
148
121
|
}
|
|
149
122
|
return payload;
|
|
150
123
|
}
|
|
151
|
-
|
|
152
124
|
export class WecomDocClient {
|
|
153
|
-
|
|
154
|
-
path: string;
|
|
155
|
-
actionLabel: string;
|
|
156
|
-
agent: ResolvedAgentAccount;
|
|
157
|
-
body: Record<string, unknown> | unknown[];
|
|
158
|
-
}): Promise<any> {
|
|
125
|
+
async postWecomDocApi(params) {
|
|
159
126
|
const { path, actionLabel, agent, body } = params;
|
|
160
|
-
|
|
161
127
|
const token = await getAccessToken(agent);
|
|
162
128
|
const url = `https://qyapi.weixin.qq.com${path}?access_token=${encodeURIComponent(token)}`;
|
|
163
129
|
const proxyUrl = resolveWecomEgressProxyUrlFromNetwork(agent.network);
|
|
164
|
-
|
|
165
|
-
let lastErr: any;
|
|
130
|
+
let lastErr;
|
|
166
131
|
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
167
132
|
try {
|
|
168
133
|
const res = await wecomFetch(url, {
|
|
@@ -172,9 +137,9 @@ export class WecomDocClient {
|
|
|
172
137
|
},
|
|
173
138
|
body: JSON.stringify(body ?? {}),
|
|
174
139
|
}, { proxyUrl, timeoutMs: LIMITS.REQUEST_TIMEOUT_MS });
|
|
175
|
-
|
|
176
140
|
return await parseJsonResponse(res, actionLabel);
|
|
177
|
-
}
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
178
143
|
lastErr = err;
|
|
179
144
|
if (attempt < 3) {
|
|
180
145
|
await new Promise(r => setTimeout(r, 1000));
|
|
@@ -183,20 +148,21 @@ export class WecomDocClient {
|
|
|
183
148
|
}
|
|
184
149
|
throw lastErr;
|
|
185
150
|
}
|
|
186
|
-
|
|
187
|
-
async createDoc(params: { agent: ResolvedAgentAccount; docName: string; docType?: unknown; spaceId?: string; fatherId?: string; adminUsers?: string[] }) {
|
|
151
|
+
async createDoc(params) {
|
|
188
152
|
const { agent, docName, docType, spaceId, fatherId, adminUsers } = params;
|
|
189
153
|
const normalizedDocType = normalizeDocType(docType);
|
|
190
|
-
const payload
|
|
154
|
+
const payload = {
|
|
191
155
|
doc_type: normalizedDocType,
|
|
192
156
|
doc_name: readString(docName),
|
|
193
157
|
};
|
|
194
|
-
if (!payload.doc_name)
|
|
158
|
+
if (!payload.doc_name)
|
|
159
|
+
throw new Error("docName required");
|
|
195
160
|
const normalizedSpaceId = readString(spaceId);
|
|
196
161
|
const normalizedFatherId = readString(fatherId);
|
|
197
|
-
if (normalizedSpaceId)
|
|
198
|
-
|
|
199
|
-
|
|
162
|
+
if (normalizedSpaceId)
|
|
163
|
+
payload.spaceid = normalizedSpaceId;
|
|
164
|
+
if (normalizedFatherId)
|
|
165
|
+
payload.fatherid = normalizedFatherId;
|
|
200
166
|
// admin_users is required for smart_table to ensure proper permissions
|
|
201
167
|
const normalizedAdminUsers = Array.isArray(adminUsers)
|
|
202
168
|
? adminUsers.map((item) => readString(item)).filter(Boolean)
|
|
@@ -204,14 +170,12 @@ export class WecomDocClient {
|
|
|
204
170
|
if (normalizedAdminUsers.length > 0) {
|
|
205
171
|
payload.admin_users = normalizedAdminUsers;
|
|
206
172
|
}
|
|
207
|
-
|
|
208
173
|
const json = await this.postWecomDocApi({
|
|
209
174
|
path: "/cgi-bin/wedoc/create_doc",
|
|
210
175
|
actionLabel: "create_doc",
|
|
211
176
|
agent,
|
|
212
177
|
body: payload,
|
|
213
178
|
});
|
|
214
|
-
|
|
215
179
|
const result = {
|
|
216
180
|
raw: json,
|
|
217
181
|
docId: readString(json.docid),
|
|
@@ -219,15 +183,12 @@ export class WecomDocClient {
|
|
|
219
183
|
docType: normalizedDocType,
|
|
220
184
|
docTypeLabel: mapDocTypeLabel(normalizedDocType),
|
|
221
185
|
};
|
|
222
|
-
|
|
223
186
|
// Auto-initialize smart_table: clean up default fields and records
|
|
224
187
|
if (normalizedDocType === 10) {
|
|
225
188
|
await this.initializeSmartTable({ agent, docId: result.docId });
|
|
226
189
|
}
|
|
227
|
-
|
|
228
190
|
return result;
|
|
229
191
|
}
|
|
230
|
-
|
|
231
192
|
/**
|
|
232
193
|
* Initialize smart_table after creation:
|
|
233
194
|
* 1. Get default sheet (smartsheet type)
|
|
@@ -236,21 +197,18 @@ export class WecomDocClient {
|
|
|
236
197
|
* 4. Get default records (usually 5 empty records)
|
|
237
198
|
* 5. Delete all default records
|
|
238
199
|
*/
|
|
239
|
-
|
|
200
|
+
async initializeSmartTable(params) {
|
|
240
201
|
const { agent, docId } = params;
|
|
241
|
-
|
|
242
202
|
try {
|
|
243
203
|
// Step 1: Get sheet list to find the default smartsheet
|
|
244
204
|
const sheetsResult = await this.smartTableGetSheets({ agent, docId });
|
|
245
|
-
const defaultSheet = sheetsResult.sheets.find((s
|
|
246
|
-
if (!defaultSheet)
|
|
247
|
-
|
|
248
|
-
const sheetId =
|
|
249
|
-
|
|
205
|
+
const defaultSheet = sheetsResult.sheets.find((s) => s.type === "smartsheet");
|
|
206
|
+
if (!defaultSheet)
|
|
207
|
+
return; // No smartsheet found, skip initialization
|
|
208
|
+
const sheetId = defaultSheet.sheet_id;
|
|
250
209
|
// Step 2: Get default fields
|
|
251
210
|
const fieldsResult = await this.smartTableGetFields({ agent, docId, sheetId });
|
|
252
211
|
const fields = fieldsResult.fields || [];
|
|
253
|
-
|
|
254
212
|
if (fields.length > 1) {
|
|
255
213
|
// Keep the last field as primary key, delete the rest
|
|
256
214
|
// Primary key capable types: TEXT, NUMBER, DATE_TIME, URL, PROGRESS, EMAIL, PHONE_NUMBER, FORMULA, LOCATION, CURRENCY, AUTONUMBER, TITLE, WWGROUP
|
|
@@ -260,58 +218,55 @@ export class WecomDocClient {
|
|
|
260
218
|
'FIELD_TYPE_PHONE_NUMBER', 'FIELD_TYPE_LOCATION', 'FIELD_TYPE_CURRENCY',
|
|
261
219
|
'FIELD_TYPE_AUTONUMBER', 'FIELD_TYPE_WWGROUP'
|
|
262
220
|
];
|
|
263
|
-
|
|
264
221
|
// Find a field that can be primary key (prefer the last one)
|
|
265
|
-
let fieldToDelete
|
|
266
|
-
let fieldToKeep
|
|
267
|
-
|
|
222
|
+
let fieldToDelete = [];
|
|
223
|
+
let fieldToKeep = null;
|
|
268
224
|
for (let i = fields.length - 1; i >= 0; i--) {
|
|
269
|
-
const field = fields[i]
|
|
225
|
+
const field = fields[i];
|
|
270
226
|
if (!fieldToKeep && primaryKeyCapableTypes.includes(field.field_type)) {
|
|
271
227
|
fieldToKeep = field.field_id;
|
|
272
|
-
}
|
|
228
|
+
}
|
|
229
|
+
else if (field.field_id) {
|
|
273
230
|
fieldToDelete.push(field.field_id);
|
|
274
231
|
}
|
|
275
232
|
}
|
|
276
|
-
|
|
277
233
|
// If no primary key capable field found, keep the last one anyway
|
|
278
234
|
if (!fieldToKeep && fields.length > 0) {
|
|
279
|
-
const lastField = fields[fields.length - 1]
|
|
235
|
+
const lastField = fields[fields.length - 1];
|
|
280
236
|
fieldToKeep = lastField.field_id;
|
|
281
|
-
fieldToDelete = fields.slice(0, -1).map((f
|
|
237
|
+
fieldToDelete = fields.slice(0, -1).map((f) => f.field_id);
|
|
282
238
|
}
|
|
283
|
-
|
|
284
239
|
// Delete the fields
|
|
285
240
|
if (fieldToDelete.length > 0) {
|
|
286
241
|
await this.smartTableDelFields({ agent, docId, sheetId, field_ids: fieldToDelete });
|
|
287
242
|
}
|
|
288
243
|
}
|
|
289
|
-
|
|
290
244
|
// Step 3: Get default records
|
|
291
245
|
const recordsResult = await this.smartTableGetRecords({ agent, docId, sheetId, limit: 100 });
|
|
292
246
|
const records = recordsResult.records || [];
|
|
293
|
-
|
|
294
247
|
if (records.length > 0) {
|
|
295
248
|
// Delete all default empty records
|
|
296
|
-
const recordIds = records.map((r
|
|
249
|
+
const recordIds = records.map((r) => r.record_id).filter(Boolean);
|
|
297
250
|
if (recordIds.length > 0) {
|
|
298
251
|
await this.smartTableDelRecords({ agent, docId, sheetId, record_ids: recordIds });
|
|
299
252
|
}
|
|
300
253
|
}
|
|
301
|
-
}
|
|
254
|
+
}
|
|
255
|
+
catch (err) {
|
|
302
256
|
// Non-fatal: smart_table created, just default cleanup failed
|
|
303
257
|
console.error(`[WecomDocClient] initializeSmartTable failed:`, err);
|
|
304
258
|
}
|
|
305
259
|
}
|
|
306
|
-
|
|
307
|
-
async renameDoc(params: { agent: ResolvedAgentAccount; docId: string; newName: string }) {
|
|
260
|
+
async renameDoc(params) {
|
|
308
261
|
const { agent, docId, newName } = params;
|
|
309
262
|
const payload = {
|
|
310
263
|
docid: readString(docId),
|
|
311
264
|
new_name: readString(newName),
|
|
312
265
|
};
|
|
313
|
-
if (!payload.docid)
|
|
314
|
-
|
|
266
|
+
if (!payload.docid)
|
|
267
|
+
throw new Error("docId required");
|
|
268
|
+
if (!payload.new_name)
|
|
269
|
+
throw new Error("newName required");
|
|
315
270
|
const json = await this.postWecomDocApi({
|
|
316
271
|
path: "/cgi-bin/wedoc/rename_doc",
|
|
317
272
|
actionLabel: "rename_doc",
|
|
@@ -324,17 +279,19 @@ export class WecomDocClient {
|
|
|
324
279
|
newName: payload.new_name,
|
|
325
280
|
};
|
|
326
281
|
}
|
|
327
|
-
|
|
328
|
-
async copyDoc(params: { agent: ResolvedAgentAccount; docId: string; newName?: string; spaceId?: string; fatherId?: string }) {
|
|
282
|
+
async copyDoc(params) {
|
|
329
283
|
const { agent, docId, newName, spaceId, fatherId } = params;
|
|
330
|
-
const payload
|
|
284
|
+
const payload = {
|
|
331
285
|
docid: readString(docId),
|
|
332
286
|
};
|
|
333
|
-
if (!payload.docid)
|
|
334
|
-
|
|
335
|
-
if (
|
|
336
|
-
|
|
337
|
-
|
|
287
|
+
if (!payload.docid)
|
|
288
|
+
throw new Error("docId required");
|
|
289
|
+
if (newName)
|
|
290
|
+
payload.new_name = readString(newName);
|
|
291
|
+
if (spaceId)
|
|
292
|
+
payload.spaceid = readString(spaceId);
|
|
293
|
+
if (fatherId)
|
|
294
|
+
payload.fatherid = readString(fatherId);
|
|
338
295
|
const json = await this.postWecomDocApi({
|
|
339
296
|
path: "/cgi-bin/wedoc/smartsheet/copy",
|
|
340
297
|
actionLabel: "copy_smartsheet",
|
|
@@ -347,11 +304,11 @@ export class WecomDocClient {
|
|
|
347
304
|
url: readString(json.url),
|
|
348
305
|
};
|
|
349
306
|
}
|
|
350
|
-
|
|
351
|
-
async getDocBaseInfo(params: { agent: ResolvedAgentAccount; docId: string }) {
|
|
307
|
+
async getDocBaseInfo(params) {
|
|
352
308
|
const { agent, docId } = params;
|
|
353
309
|
const normalizedDocId = readString(docId);
|
|
354
|
-
if (!normalizedDocId)
|
|
310
|
+
if (!normalizedDocId)
|
|
311
|
+
throw new Error("docId required");
|
|
355
312
|
const json = await this.postWecomDocApi({
|
|
356
313
|
path: "/cgi-bin/wedoc/get_doc_base_info",
|
|
357
314
|
actionLabel: "get_doc_base_info",
|
|
@@ -363,11 +320,11 @@ export class WecomDocClient {
|
|
|
363
320
|
info: json.doc_base_info && typeof json.doc_base_info === "object" ? json.doc_base_info : {},
|
|
364
321
|
};
|
|
365
322
|
}
|
|
366
|
-
|
|
367
|
-
async shareDoc(params: { agent: ResolvedAgentAccount; docId: string }) {
|
|
323
|
+
async shareDoc(params) {
|
|
368
324
|
const { agent, docId } = params;
|
|
369
325
|
const normalizedDocId = readString(docId);
|
|
370
|
-
if (!normalizedDocId)
|
|
326
|
+
if (!normalizedDocId)
|
|
327
|
+
throw new Error("docId required");
|
|
371
328
|
const json = await this.postWecomDocApi({
|
|
372
329
|
path: "/cgi-bin/wedoc/doc_share",
|
|
373
330
|
actionLabel: "doc_share",
|
|
@@ -379,11 +336,11 @@ export class WecomDocClient {
|
|
|
379
336
|
shareUrl: readString(json.share_url),
|
|
380
337
|
};
|
|
381
338
|
}
|
|
382
|
-
|
|
383
|
-
async getDocAuth(params: { agent: ResolvedAgentAccount; docId: string }) {
|
|
339
|
+
async getDocAuth(params) {
|
|
384
340
|
const { agent, docId } = params;
|
|
385
341
|
const normalizedDocId = readString(docId);
|
|
386
|
-
if (!normalizedDocId)
|
|
342
|
+
if (!normalizedDocId)
|
|
343
|
+
throw new Error("docId required");
|
|
387
344
|
const json = await this.postWecomDocApi({
|
|
388
345
|
path: "/cgi-bin/wedoc/doc_get_auth",
|
|
389
346
|
actionLabel: "doc_get_auth",
|
|
@@ -398,14 +355,15 @@ export class WecomDocClient {
|
|
|
398
355
|
coAuthList: Array.isArray(json.co_auth_list) ? json.co_auth_list : [],
|
|
399
356
|
};
|
|
400
357
|
}
|
|
401
|
-
|
|
402
|
-
async deleteDoc(params: { agent: ResolvedAgentAccount; docId?: string; formId?: string }) {
|
|
358
|
+
async deleteDoc(params) {
|
|
403
359
|
const { agent, docId, formId } = params;
|
|
404
|
-
const payload
|
|
360
|
+
const payload = {};
|
|
405
361
|
const normalizedDocId = readString(docId);
|
|
406
362
|
const normalizedFormId = readString(formId);
|
|
407
|
-
if (normalizedDocId)
|
|
408
|
-
|
|
363
|
+
if (normalizedDocId)
|
|
364
|
+
payload.docid = normalizedDocId;
|
|
365
|
+
if (normalizedFormId)
|
|
366
|
+
payload.formid = normalizedFormId;
|
|
409
367
|
if (!payload.docid && !payload.formid) {
|
|
410
368
|
throw new Error("docId or formId required");
|
|
411
369
|
}
|
|
@@ -421,14 +379,14 @@ export class WecomDocClient {
|
|
|
421
379
|
formId: payload.formid || "",
|
|
422
380
|
};
|
|
423
381
|
}
|
|
424
|
-
|
|
425
|
-
async setDocJoinRule(params: { agent: ResolvedAgentAccount; docId: string; request: any }) {
|
|
382
|
+
async setDocJoinRule(params) {
|
|
426
383
|
const { agent, docId, request } = params;
|
|
427
384
|
const payload = {
|
|
428
385
|
...readObject(request),
|
|
429
386
|
};
|
|
430
387
|
payload.docid = readString(docId || payload.docid);
|
|
431
|
-
if (!payload.docid)
|
|
388
|
+
if (!payload.docid)
|
|
389
|
+
throw new Error("docId required");
|
|
432
390
|
const json = await this.postWecomDocApi({
|
|
433
391
|
path: "/cgi-bin/wedoc/mod_doc_join_rule",
|
|
434
392
|
actionLabel: "mod_doc_join_rule",
|
|
@@ -437,17 +395,17 @@ export class WecomDocClient {
|
|
|
437
395
|
});
|
|
438
396
|
return {
|
|
439
397
|
raw: json,
|
|
440
|
-
docId: payload.docid
|
|
398
|
+
docId: payload.docid,
|
|
441
399
|
};
|
|
442
400
|
}
|
|
443
|
-
|
|
444
|
-
async setDocMemberAuth(params: { agent: ResolvedAgentAccount; docId: string; request: any }) {
|
|
401
|
+
async setDocMemberAuth(params) {
|
|
445
402
|
const { agent, docId, request } = params;
|
|
446
403
|
const payload = {
|
|
447
404
|
...readObject(request),
|
|
448
405
|
};
|
|
449
406
|
payload.docid = readString(docId || payload.docid);
|
|
450
|
-
if (!payload.docid)
|
|
407
|
+
if (!payload.docid)
|
|
408
|
+
throw new Error("docId required");
|
|
451
409
|
const json = await this.postWecomDocApi({
|
|
452
410
|
path: "/cgi-bin/wedoc/mod_doc_member",
|
|
453
411
|
actionLabel: "mod_doc_member",
|
|
@@ -456,21 +414,11 @@ export class WecomDocClient {
|
|
|
456
414
|
});
|
|
457
415
|
return {
|
|
458
416
|
raw: json,
|
|
459
|
-
docId: payload.docid
|
|
417
|
+
docId: payload.docid,
|
|
460
418
|
};
|
|
461
419
|
}
|
|
462
|
-
|
|
463
|
-
async grantDocAccess(params: {
|
|
464
|
-
agent: ResolvedAgentAccount;
|
|
465
|
-
docId: string;
|
|
466
|
-
viewers?: unknown;
|
|
467
|
-
collaborators?: unknown;
|
|
468
|
-
removeViewers?: unknown;
|
|
469
|
-
removeCollaborators?: unknown;
|
|
470
|
-
authLevel?: number;
|
|
471
|
-
}) {
|
|
420
|
+
async grantDocAccess(params) {
|
|
472
421
|
const { agent, docId, viewers, collaborators, removeViewers, removeCollaborators, authLevel } = params;
|
|
473
|
-
|
|
474
422
|
// Auto-detect: if adding collaborators, check if they are already viewers and need to be removed
|
|
475
423
|
// This prevents the "user is viewer but not collaborator" issue
|
|
476
424
|
let finalRemoveViewers = removeViewers;
|
|
@@ -479,32 +427,29 @@ export class WecomDocClient {
|
|
|
479
427
|
try {
|
|
480
428
|
const currentAuth = await this.getDocAuth({ agent, docId });
|
|
481
429
|
// Build a map of viewer entries with their full structure (preserving type and other fields)
|
|
482
|
-
const viewerMap = new Map
|
|
430
|
+
const viewerMap = new Map();
|
|
483
431
|
(currentAuth.docMembers || [])
|
|
484
|
-
.filter((m
|
|
485
|
-
.forEach((m
|
|
486
|
-
|
|
432
|
+
.filter((m) => m.userid)
|
|
433
|
+
.forEach((m) => viewerMap.set(m.userid, m));
|
|
487
434
|
// Normalize new collaborators to get their userids
|
|
488
435
|
const newCollaboratorEntries = normalizeDocMemberEntryList(collaborators);
|
|
489
|
-
|
|
490
436
|
// Auto-add viewers who are being promoted to collaborators, preserving their original structure
|
|
491
437
|
const autoRemoveViewers = newCollaboratorEntries
|
|
492
438
|
.filter(entry => entry.userid && viewerMap.has(entry.userid))
|
|
493
439
|
.map(entry => {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
440
|
+
// Preserve the original viewer's full structure (type, userid, etc.)
|
|
441
|
+
const originalViewer = viewerMap.get(entry.userid);
|
|
442
|
+
return { ...originalViewer };
|
|
443
|
+
});
|
|
499
444
|
if (autoRemoveViewers.length > 0) {
|
|
500
445
|
finalRemoveViewers = autoRemoveViewers;
|
|
501
446
|
}
|
|
502
|
-
}
|
|
447
|
+
}
|
|
448
|
+
catch (err) {
|
|
503
449
|
// If we can't check auth, proceed without auto-removal
|
|
504
450
|
// The caller can explicitly pass removeViewers if needed
|
|
505
451
|
}
|
|
506
452
|
}
|
|
507
|
-
|
|
508
453
|
const payload = buildDocMemberAuthRequest({
|
|
509
454
|
docId,
|
|
510
455
|
viewers,
|
|
@@ -515,19 +460,18 @@ export class WecomDocClient {
|
|
|
515
460
|
});
|
|
516
461
|
const result = await this.setDocMemberAuth({
|
|
517
462
|
agent,
|
|
518
|
-
docId: payload.docid
|
|
463
|
+
docId: payload.docid,
|
|
519
464
|
request: payload,
|
|
520
465
|
});
|
|
521
466
|
return {
|
|
522
467
|
...result,
|
|
523
|
-
addedViewerCount:
|
|
524
|
-
addedCollaboratorCount:
|
|
525
|
-
removedViewerCount:
|
|
526
|
-
removedCollaboratorCount:
|
|
468
|
+
addedViewerCount: payload.update_file_member_list?.length ?? 0,
|
|
469
|
+
addedCollaboratorCount: payload.update_co_auth_list?.length ?? 0,
|
|
470
|
+
removedViewerCount: payload.del_file_member_list?.length ?? 0,
|
|
471
|
+
removedCollaboratorCount: payload.del_co_auth_list?.length ?? 0,
|
|
527
472
|
};
|
|
528
473
|
}
|
|
529
|
-
|
|
530
|
-
async addDocCollaborators(params: { agent: ResolvedAgentAccount; docId: string; collaborators: unknown; auth?: number }) {
|
|
474
|
+
async addDocCollaborators(params) {
|
|
531
475
|
const { agent, docId, collaborators, auth } = params;
|
|
532
476
|
return this.grantDocAccess({
|
|
533
477
|
agent,
|
|
@@ -536,14 +480,14 @@ export class WecomDocClient {
|
|
|
536
480
|
authLevel: auth ?? 2, // Default to edit/read-write for collaborators
|
|
537
481
|
});
|
|
538
482
|
}
|
|
539
|
-
|
|
540
|
-
async setDocSafetySetting(params: { agent: ResolvedAgentAccount; docId: string; request: any }) {
|
|
483
|
+
async setDocSafetySetting(params) {
|
|
541
484
|
const { agent, docId, request } = params;
|
|
542
485
|
const payload = {
|
|
543
486
|
...readObject(request),
|
|
544
487
|
};
|
|
545
488
|
payload.docid = readString(docId || payload.docid);
|
|
546
|
-
if (!payload.docid)
|
|
489
|
+
if (!payload.docid)
|
|
490
|
+
throw new Error("docId required");
|
|
547
491
|
const json = await this.postWecomDocApi({
|
|
548
492
|
path: "/cgi-bin/wedoc/mod_doc_safty_setting",
|
|
549
493
|
actionLabel: "mod_doc_safty_setting",
|
|
@@ -552,45 +496,40 @@ export class WecomDocClient {
|
|
|
552
496
|
});
|
|
553
497
|
return {
|
|
554
498
|
raw: json,
|
|
555
|
-
docId: payload.docid
|
|
499
|
+
docId: payload.docid,
|
|
556
500
|
};
|
|
557
501
|
}
|
|
558
|
-
|
|
559
|
-
async createCollect(params: { agent: ResolvedAgentAccount; formInfo: any; spaceId?: string; fatherId?: string }) {
|
|
502
|
+
async createCollect(params) {
|
|
560
503
|
const { agent, formInfo, spaceId, fatherId } = params;
|
|
561
|
-
|
|
562
504
|
// Validate form_info structure per API spec
|
|
563
505
|
if (!formInfo || typeof formInfo !== 'object') {
|
|
564
506
|
throw new Error("formInfo 必须是非空对象");
|
|
565
507
|
}
|
|
566
|
-
|
|
567
508
|
// Validate required fields
|
|
568
509
|
if (!formInfo.form_title || readString(formInfo.form_title).length === 0) {
|
|
569
510
|
throw new Error("form_title 必填");
|
|
570
511
|
}
|
|
571
|
-
|
|
572
512
|
if (!formInfo.form_question || !formInfo.form_question.items || !Array.isArray(formInfo.form_question.items)) {
|
|
573
513
|
throw new Error("form_question.items 必填且必须为数组");
|
|
574
514
|
}
|
|
575
|
-
|
|
576
515
|
// Validate questions count ≤ 200
|
|
577
516
|
const questions = formInfo.form_question.items;
|
|
578
517
|
if (questions.length > 200) {
|
|
579
518
|
throw new Error("问题数量不能超过 200 个");
|
|
580
519
|
}
|
|
581
|
-
|
|
582
520
|
// Auto-fill status fields for questions and options
|
|
583
|
-
questions.forEach((q
|
|
584
|
-
if (q.status === undefined)
|
|
521
|
+
questions.forEach((q) => {
|
|
522
|
+
if (q.status === undefined)
|
|
523
|
+
q.status = 1;
|
|
585
524
|
if (Array.isArray(q.option_item)) {
|
|
586
|
-
q.option_item.forEach((opt
|
|
587
|
-
if (opt.status === undefined)
|
|
525
|
+
q.option_item.forEach((opt) => {
|
|
526
|
+
if (opt.status === undefined)
|
|
527
|
+
opt.status = 1;
|
|
588
528
|
});
|
|
589
529
|
}
|
|
590
530
|
});
|
|
591
|
-
|
|
592
531
|
// Validate each question
|
|
593
|
-
questions.forEach((q
|
|
532
|
+
questions.forEach((q, index) => {
|
|
594
533
|
if (!q.question_id || !Number.isInteger(q.question_id) || q.question_id < 1) {
|
|
595
534
|
throw new Error(`第${index + 1}个问题:question_id 必填且必须从 1 开始`);
|
|
596
535
|
}
|
|
@@ -609,7 +548,6 @@ export class WecomDocClient {
|
|
|
609
548
|
if (q.status !== undefined && ![1, 2].includes(q.status)) {
|
|
610
549
|
throw new Error(`第${index + 1}个问题:status 必须为 1(正常) 或 2(删除)`);
|
|
611
550
|
}
|
|
612
|
-
|
|
613
551
|
// Validate option_item for single/multiple/dropdown questions
|
|
614
552
|
const requiresOptions = [2, 3, 15].includes(q.reply_type); // 单选/多选/下拉列表
|
|
615
553
|
if (requiresOptions) {
|
|
@@ -617,7 +555,7 @@ export class WecomDocClient {
|
|
|
617
555
|
throw new Error(`第${index + 1}个问题:单选/多选/下拉列表必须提供 option_item 数组`);
|
|
618
556
|
}
|
|
619
557
|
// Validate option keys are sequential from 1
|
|
620
|
-
q.option_item.forEach((opt
|
|
558
|
+
q.option_item.forEach((opt, optIndex) => {
|
|
621
559
|
if (!opt.key || !Number.isInteger(opt.key) || opt.key < 1) {
|
|
622
560
|
throw new Error(`第${index + 1}个问题的第${optIndex + 1}个选项:key 必填且从 1 开始`);
|
|
623
561
|
}
|
|
@@ -629,7 +567,6 @@ export class WecomDocClient {
|
|
|
629
567
|
}
|
|
630
568
|
});
|
|
631
569
|
}
|
|
632
|
-
|
|
633
570
|
// Validate image/file upload limits
|
|
634
571
|
if ([9, 10].includes(q.reply_type)) { // 图片/文件
|
|
635
572
|
const setting = q.question_extend_setting;
|
|
@@ -646,22 +583,19 @@ export class WecomDocClient {
|
|
|
646
583
|
}
|
|
647
584
|
}
|
|
648
585
|
});
|
|
649
|
-
|
|
650
586
|
// Validate timed_repeat_info and timed_finish are mutually exclusive
|
|
651
587
|
const formSetting = formInfo.form_setting || {};
|
|
652
588
|
if (formSetting.timed_repeat_info?.enable && formSetting.timed_finish) {
|
|
653
589
|
console.warn("警告:timed_finish 与 timed_repeat_info 互斥,若都填优先定时重复");
|
|
654
590
|
}
|
|
655
|
-
|
|
656
591
|
// Validate timed_repeat_info.enable=true requires fill_in_range
|
|
657
592
|
if (formSetting.timed_repeat_info?.enable) {
|
|
658
593
|
if (!formSetting.fill_in_range || (!formSetting.fill_in_range.userids?.length && !formSetting.fill_in_range.departmentids?.length)) {
|
|
659
594
|
throw new Error("timed_repeat_info 开启时,fill_in_range 必填(需指定 userids 或 departmentids)");
|
|
660
595
|
}
|
|
661
596
|
}
|
|
662
|
-
|
|
663
597
|
// Build payload
|
|
664
|
-
const payload
|
|
598
|
+
const payload = {
|
|
665
599
|
form_info: {
|
|
666
600
|
form_title: readString(formInfo.form_title),
|
|
667
601
|
form_desc: formInfo.form_desc ? readString(formInfo.form_desc) : undefined,
|
|
@@ -670,12 +604,12 @@ export class WecomDocClient {
|
|
|
670
604
|
form_setting: formSetting,
|
|
671
605
|
},
|
|
672
606
|
};
|
|
673
|
-
|
|
674
607
|
const normalizedSpaceId = readString(spaceId);
|
|
675
608
|
const normalizedFatherId = readString(fatherId);
|
|
676
|
-
if (normalizedSpaceId)
|
|
677
|
-
|
|
678
|
-
|
|
609
|
+
if (normalizedSpaceId)
|
|
610
|
+
payload.spaceid = normalizedSpaceId;
|
|
611
|
+
if (normalizedFatherId)
|
|
612
|
+
payload.fatherid = normalizedFatherId;
|
|
679
613
|
const json = await this.postWecomDocApi({
|
|
680
614
|
path: "/cgi-bin/wedoc/create_form",
|
|
681
615
|
actionLabel: "create_form",
|
|
@@ -685,52 +619,47 @@ export class WecomDocClient {
|
|
|
685
619
|
return {
|
|
686
620
|
raw: json,
|
|
687
621
|
formId: readString(json.formid),
|
|
688
|
-
title: readString(
|
|
622
|
+
title: readString(payload.form_info.form_title),
|
|
689
623
|
};
|
|
690
624
|
}
|
|
691
|
-
|
|
692
|
-
async modifyCollect(params: { agent: ResolvedAgentAccount; oper: string; formId: string; formInfo: any }) {
|
|
625
|
+
async modifyCollect(params) {
|
|
693
626
|
const { agent, oper, formId, formInfo } = params;
|
|
694
|
-
|
|
695
627
|
// Validate oper parameter
|
|
696
628
|
const operNum = Number(oper);
|
|
697
629
|
if (!operNum || ![1, 2].includes(operNum)) {
|
|
698
630
|
throw new Error("oper 必填且必须为 1 或 2:1=全量修改问题,2=全量修改设置");
|
|
699
631
|
}
|
|
700
|
-
|
|
701
632
|
const normalizedFormId = readString(formId);
|
|
702
|
-
if (!normalizedFormId)
|
|
703
|
-
|
|
633
|
+
if (!normalizedFormId)
|
|
634
|
+
throw new Error("formId required");
|
|
704
635
|
// Build payload based on oper type
|
|
705
|
-
const payload
|
|
636
|
+
const payload = {
|
|
706
637
|
oper: operNum,
|
|
707
638
|
formid: normalizedFormId,
|
|
708
639
|
};
|
|
709
|
-
|
|
710
640
|
if (operNum === 1) {
|
|
711
641
|
// 全量修改问题:必须提供完整的 form_question 数组
|
|
712
642
|
if (!formInfo || !formInfo.form_question || !Array.isArray(formInfo.form_question.items)) {
|
|
713
643
|
throw new Error("oper=1 时,必须提供 form_question.items 数组(包含所有问题,缺失的问题将被删除)");
|
|
714
644
|
}
|
|
715
|
-
|
|
716
645
|
// Validate questions count ≤ 200
|
|
717
646
|
const questions = formInfo.form_question.items;
|
|
718
647
|
if (questions.length > 200) {
|
|
719
648
|
throw new Error("问题数量不能超过 200 个");
|
|
720
649
|
}
|
|
721
|
-
|
|
722
650
|
// Auto-fill status fields for questions and options
|
|
723
|
-
questions.forEach((q
|
|
724
|
-
if (q.status === undefined)
|
|
651
|
+
questions.forEach((q) => {
|
|
652
|
+
if (q.status === undefined)
|
|
653
|
+
q.status = 1;
|
|
725
654
|
if (Array.isArray(q.option_item)) {
|
|
726
|
-
q.option_item.forEach((opt
|
|
727
|
-
if (opt.status === undefined)
|
|
655
|
+
q.option_item.forEach((opt) => {
|
|
656
|
+
if (opt.status === undefined)
|
|
657
|
+
opt.status = 1;
|
|
728
658
|
});
|
|
729
659
|
}
|
|
730
660
|
});
|
|
731
|
-
|
|
732
661
|
// Validate each question (same as createCollect)
|
|
733
|
-
questions.forEach((q
|
|
662
|
+
questions.forEach((q, index) => {
|
|
734
663
|
if (!q.question_id || !Number.isInteger(q.question_id) || q.question_id < 1) {
|
|
735
664
|
throw new Error(`第${index + 1}个问题:question_id 必填且必须从 1 开始`);
|
|
736
665
|
}
|
|
@@ -746,14 +675,13 @@ export class WecomDocClient {
|
|
|
746
675
|
if (q.must_reply === undefined || typeof q.must_reply !== 'boolean') {
|
|
747
676
|
throw new Error(`第${index + 1}个问题:must_reply 必填且必须为布尔值`);
|
|
748
677
|
}
|
|
749
|
-
|
|
750
678
|
// Validate option_item for single/multiple/dropdown questions
|
|
751
679
|
const requiresOptions = [2, 3, 15].includes(q.reply_type);
|
|
752
680
|
if (requiresOptions) {
|
|
753
681
|
if (!Array.isArray(q.option_item) || q.option_item.length === 0) {
|
|
754
682
|
throw new Error(`第${index + 1}个问题:单选/多选/下拉列表必须提供 option_item 数组`);
|
|
755
683
|
}
|
|
756
|
-
q.option_item.forEach((opt
|
|
684
|
+
q.option_item.forEach((opt, optIndex) => {
|
|
757
685
|
if (!opt.key || !Number.isInteger(opt.key) || opt.key < 1) {
|
|
758
686
|
throw new Error(`第${index + 1}个问题的第${optIndex + 1}个选项:key 必填且从 1 开始`);
|
|
759
687
|
}
|
|
@@ -763,24 +691,20 @@ export class WecomDocClient {
|
|
|
763
691
|
});
|
|
764
692
|
}
|
|
765
693
|
});
|
|
766
|
-
|
|
767
694
|
payload.form_info = { form_question: formInfo.form_question };
|
|
768
|
-
|
|
769
|
-
|
|
695
|
+
}
|
|
696
|
+
else if (operNum === 2) {
|
|
770
697
|
// 全量修改设置:必须提供完整的 form_setting 对象
|
|
771
698
|
if (!formInfo || !formInfo.form_setting || typeof formInfo.form_setting !== 'object') {
|
|
772
699
|
throw new Error("oper=2 时,必须提供 form_setting 对象(缺失的设置项将被重置为默认值)");
|
|
773
700
|
}
|
|
774
|
-
|
|
775
701
|
// Validate timed_repeat_info and timed_finish are mutually exclusive
|
|
776
702
|
const formSetting = formInfo.form_setting;
|
|
777
703
|
if (formSetting.timed_repeat_info?.enable && formSetting.timed_finish) {
|
|
778
704
|
console.warn("警告:timed_finish 与 timed_repeat_info 互斥,若都填优先定时重复");
|
|
779
705
|
}
|
|
780
|
-
|
|
781
706
|
payload.form_info = { form_setting: formSetting };
|
|
782
707
|
}
|
|
783
|
-
|
|
784
708
|
const json = await this.postWecomDocApi({
|
|
785
709
|
path: "/cgi-bin/wedoc/modify_form",
|
|
786
710
|
actionLabel: "modify_form",
|
|
@@ -789,16 +713,16 @@ export class WecomDocClient {
|
|
|
789
713
|
});
|
|
790
714
|
return {
|
|
791
715
|
raw: json,
|
|
792
|
-
formId: payload.formid
|
|
793
|
-
oper: payload.oper
|
|
716
|
+
formId: payload.formid,
|
|
717
|
+
oper: payload.oper,
|
|
794
718
|
title: formInfo?.form_title ? readString(formInfo.form_title) : undefined,
|
|
795
719
|
};
|
|
796
720
|
}
|
|
797
|
-
|
|
798
|
-
async getFormInfo(params: { agent: ResolvedAgentAccount; formId: string }) {
|
|
721
|
+
async getFormInfo(params) {
|
|
799
722
|
const { agent, formId } = params;
|
|
800
723
|
const normalizedFormId = readString(formId);
|
|
801
|
-
if (!normalizedFormId)
|
|
724
|
+
if (!normalizedFormId)
|
|
725
|
+
throw new Error("formId required");
|
|
802
726
|
const json = await this.postWecomDocApi({
|
|
803
727
|
path: "/cgi-bin/wedoc/get_form_info",
|
|
804
728
|
actionLabel: "get_form_info",
|
|
@@ -810,23 +734,21 @@ export class WecomDocClient {
|
|
|
810
734
|
formInfo: readObject(json.form_info),
|
|
811
735
|
};
|
|
812
736
|
}
|
|
813
|
-
|
|
814
|
-
async getFormAnswer(params: { agent: ResolvedAgentAccount; repeatedId: string; answerIds?: unknown[] }) {
|
|
737
|
+
async getFormAnswer(params) {
|
|
815
738
|
const { agent, repeatedId, answerIds } = params;
|
|
816
739
|
const normalizedRepeatedId = readString(repeatedId);
|
|
817
|
-
if (!normalizedRepeatedId)
|
|
740
|
+
if (!normalizedRepeatedId)
|
|
741
|
+
throw new Error("repeatedId required");
|
|
818
742
|
const normalizedAnswerIds = Array.isArray(answerIds)
|
|
819
743
|
? answerIds
|
|
820
744
|
.map((item) => Number(item))
|
|
821
745
|
.filter((item) => Number.isFinite(item))
|
|
822
746
|
: [];
|
|
823
|
-
|
|
824
747
|
// Official API limit: ≤100 answer IDs
|
|
825
748
|
if (normalizedAnswerIds.length > 100) {
|
|
826
749
|
throw new Error(`answer_ids 不能超过 100 个,当前:${normalizedAnswerIds.length}`);
|
|
827
750
|
}
|
|
828
|
-
|
|
829
|
-
const payload: Record<string, unknown> = {
|
|
751
|
+
const payload = {
|
|
830
752
|
repeated_id: normalizedRepeatedId,
|
|
831
753
|
};
|
|
832
754
|
if (normalizedAnswerIds.length > 0) {
|
|
@@ -842,11 +764,10 @@ export class WecomDocClient {
|
|
|
842
764
|
return {
|
|
843
765
|
raw: json,
|
|
844
766
|
answer,
|
|
845
|
-
answerList: readArray(
|
|
767
|
+
answerList: readArray(answer.answer_list),
|
|
846
768
|
};
|
|
847
769
|
}
|
|
848
|
-
|
|
849
|
-
async getFormStatistic(params: { agent: ResolvedAgentAccount; requests: unknown[] }) {
|
|
770
|
+
async getFormStatistic(params) {
|
|
850
771
|
const { agent, requests } = params;
|
|
851
772
|
const payload = Array.isArray(requests)
|
|
852
773
|
? requests.map((item) => readObject(item)).filter((item) => Object.keys(item).length > 0)
|
|
@@ -854,11 +775,9 @@ export class WecomDocClient {
|
|
|
854
775
|
if (payload.length === 0) {
|
|
855
776
|
throw new Error("requests required");
|
|
856
777
|
}
|
|
857
|
-
|
|
858
778
|
// Validate each request per official API
|
|
859
|
-
payload.forEach((req
|
|
779
|
+
payload.forEach((req, index) => {
|
|
860
780
|
const reqType = Number(req.req_type);
|
|
861
|
-
|
|
862
781
|
// req_type=2: Get submitted list - requires start_time and end_time (same day timestamps)
|
|
863
782
|
if (reqType === 2) {
|
|
864
783
|
if (!req.start_time || !req.end_time) {
|
|
@@ -873,13 +792,11 @@ export class WecomDocClient {
|
|
|
873
792
|
throw new Error(`第${index + 1}个请求:end_time 必须大于等于 start_time`);
|
|
874
793
|
}
|
|
875
794
|
}
|
|
876
|
-
|
|
877
795
|
// Validate repeated_id is present
|
|
878
796
|
if (!req.repeated_id) {
|
|
879
797
|
throw new Error(`第${index + 1}个请求:repeated_id 必填`);
|
|
880
798
|
}
|
|
881
799
|
});
|
|
882
|
-
|
|
883
800
|
const json = await this.postWecomDocApi({
|
|
884
801
|
path: "/cgi-bin/wedoc/get_form_statistic",
|
|
885
802
|
actionLabel: "get_form_statistic",
|
|
@@ -890,21 +807,18 @@ export class WecomDocClient {
|
|
|
890
807
|
return {
|
|
891
808
|
raw: json,
|
|
892
809
|
items: statisticList,
|
|
893
|
-
successCount: statisticList.filter((item
|
|
810
|
+
successCount: statisticList.filter((item) => Number(item?.errcode ?? 0) === 0).length,
|
|
894
811
|
};
|
|
895
812
|
}
|
|
896
|
-
|
|
897
813
|
// --- Content Operations (New) ---
|
|
898
|
-
|
|
899
|
-
async getDocContent(params: { agent: ResolvedAgentAccount; docId: string }) {
|
|
814
|
+
async getDocContent(params) {
|
|
900
815
|
const { agent, docId } = params;
|
|
901
816
|
const json = await this.postWecomDocApi({
|
|
902
817
|
path: "/cgi-bin/wedoc/document/get",
|
|
903
818
|
actionLabel: "get_doc_content",
|
|
904
819
|
agent,
|
|
905
820
|
body: { docid: readString(docId) },
|
|
906
|
-
})
|
|
907
|
-
|
|
821
|
+
});
|
|
908
822
|
// Ensure structure strictly matches official API: { version: number, document: Node }
|
|
909
823
|
return {
|
|
910
824
|
raw: json,
|
|
@@ -912,16 +826,13 @@ export class WecomDocClient {
|
|
|
912
826
|
document: json.document
|
|
913
827
|
};
|
|
914
828
|
}
|
|
915
|
-
|
|
916
|
-
async updateDocContent(params: { agent: ResolvedAgentAccount; docId: string; requests: UpdateRequest[]; version?: number; batchMode?: boolean }) {
|
|
829
|
+
async updateDocContent(params) {
|
|
917
830
|
const { agent, docId, requests, version } = params;
|
|
918
|
-
|
|
919
831
|
// Validate requests structure basic check
|
|
920
832
|
const requestList = readArray(requests);
|
|
921
833
|
if (requestList.length === 0) {
|
|
922
|
-
|
|
834
|
+
throw new Error("requests list cannot be empty");
|
|
923
835
|
}
|
|
924
|
-
|
|
925
836
|
// Validate version difference (≤100 per official API)
|
|
926
837
|
if (version !== undefined && version !== null) {
|
|
927
838
|
const currentContent = await this.getDocContent({ agent, docId });
|
|
@@ -930,9 +841,8 @@ export class WecomDocClient {
|
|
|
930
841
|
throw new Error(`version 与最新版本差值不能超过 100(当前版本:${currentContent.version},传入版本:${version},差值:${versionDiff})`);
|
|
931
842
|
}
|
|
932
843
|
}
|
|
933
|
-
|
|
934
844
|
// Validate each request's ranges count (≤10 per official API)
|
|
935
|
-
requestList.forEach((req
|
|
845
|
+
requestList.forEach((req, index) => {
|
|
936
846
|
if (req.replace_text?.ranges && req.replace_text.ranges.length > 10) {
|
|
937
847
|
throw new Error(`第${index + 1}个操作:replace_text.ranges 不能超过 10 个`);
|
|
938
848
|
}
|
|
@@ -942,70 +852,65 @@ export class WecomDocClient {
|
|
|
942
852
|
// Validate insert_table limits
|
|
943
853
|
if (req.insert_table) {
|
|
944
854
|
const { rows, cols } = req.insert_table;
|
|
945
|
-
if (rows > 100)
|
|
946
|
-
|
|
947
|
-
if (
|
|
855
|
+
if (rows > 100)
|
|
856
|
+
throw new Error(`第${index + 1}个操作:insert_table 行数不能超过 100`);
|
|
857
|
+
if (cols > 60)
|
|
858
|
+
throw new Error(`第${index + 1}个操作:insert_table 列数不能超过 60`);
|
|
859
|
+
if (rows * cols > 1000)
|
|
860
|
+
throw new Error(`第${index + 1}个操作:insert_table 单元格总数不能超过 1000`);
|
|
948
861
|
}
|
|
949
862
|
});
|
|
950
|
-
|
|
951
863
|
// Official API limit: ≤30 operations per batch
|
|
952
864
|
const MAX_OPERATIONS = 30;
|
|
953
865
|
if (requestList.length <= MAX_OPERATIONS) {
|
|
954
866
|
// Single batch
|
|
955
|
-
const body
|
|
867
|
+
const body = {
|
|
956
868
|
docid: readString(docId),
|
|
957
869
|
requests: requestList,
|
|
958
870
|
};
|
|
959
871
|
if (version !== undefined && version !== null) {
|
|
960
872
|
body.version = Number(version);
|
|
961
873
|
}
|
|
962
|
-
|
|
963
874
|
const json = await this.postWecomDocApi({
|
|
964
875
|
path: "/cgi-bin/wedoc/document/batch_update",
|
|
965
876
|
actionLabel: "update_doc_content",
|
|
966
877
|
agent,
|
|
967
878
|
body,
|
|
968
|
-
})
|
|
879
|
+
});
|
|
969
880
|
return { raw: json, batches: 1 };
|
|
970
881
|
}
|
|
971
|
-
|
|
972
882
|
// Auto-batch: split into multiple requests
|
|
973
883
|
// Note: Each batch updates the version, so we need to get latest version for each batch
|
|
974
|
-
const batches
|
|
884
|
+
const batches = [];
|
|
975
885
|
for (let i = 0; i < requestList.length; i += MAX_OPERATIONS) {
|
|
976
886
|
const batchRequests = requestList.slice(i, i + MAX_OPERATIONS);
|
|
977
|
-
|
|
978
887
|
// Get latest version before each batch (except first if version provided)
|
|
979
888
|
let currentVersion = version;
|
|
980
889
|
if (i > 0 || currentVersion === undefined || currentVersion === null) {
|
|
981
890
|
const content = await this.getDocContent({ agent, docId });
|
|
982
891
|
currentVersion = content.version;
|
|
983
892
|
}
|
|
984
|
-
|
|
985
|
-
const body: Record<string, unknown> = {
|
|
893
|
+
const body = {
|
|
986
894
|
docid: readString(docId),
|
|
987
895
|
requests: batchRequests,
|
|
988
896
|
version: currentVersion,
|
|
989
897
|
};
|
|
990
|
-
|
|
991
898
|
const json = await this.postWecomDocApi({
|
|
992
899
|
path: "/cgi-bin/wedoc/document/batch_update",
|
|
993
900
|
actionLabel: `update_doc_content_batch_${Math.floor(i / MAX_OPERATIONS) + 1}`,
|
|
994
901
|
agent,
|
|
995
902
|
body,
|
|
996
|
-
})
|
|
903
|
+
});
|
|
997
904
|
batches.push(json);
|
|
998
905
|
}
|
|
999
|
-
|
|
1000
906
|
return { raw: batches[batches.length - 1], batches: batches.length, allBatches: batches };
|
|
1001
907
|
}
|
|
1002
|
-
|
|
1003
908
|
// --- Spreadsheet Operations ---
|
|
1004
|
-
|
|
1005
|
-
async getSheetProperties(params: { agent: ResolvedAgentAccount; docId: string }) {
|
|
909
|
+
async getSheetProperties(params) {
|
|
1006
910
|
const { agent, docId } = params;
|
|
1007
911
|
const normalizedDocId = readString(docId);
|
|
1008
|
-
if (!normalizedDocId)
|
|
912
|
+
if (!normalizedDocId)
|
|
913
|
+
throw new Error("docId required");
|
|
1009
914
|
const json = await this.postWecomDocApi({
|
|
1010
915
|
path: "/cgi-bin/wedoc/spreadsheet/get_sheet_properties",
|
|
1011
916
|
actionLabel: "get_sheet_properties",
|
|
@@ -1014,15 +919,13 @@ export class WecomDocClient {
|
|
|
1014
919
|
});
|
|
1015
920
|
return {
|
|
1016
921
|
raw: json,
|
|
1017
|
-
properties:
|
|
1018
|
-
(Array.isArray(json.properties) && json.properties) ||
|
|
922
|
+
properties: (Array.isArray(json.properties) && json.properties) ||
|
|
1019
923
|
(Array.isArray(json.sheet_properties) && json.sheet_properties) ||
|
|
1020
924
|
(Array.isArray(json.sheet_list) && json.sheet_list) ||
|
|
1021
925
|
[],
|
|
1022
926
|
};
|
|
1023
927
|
}
|
|
1024
|
-
|
|
1025
|
-
async modDocMemberNotifiedScope(params: { agent: ResolvedAgentAccount; docId: string; notified_scope_type: number; notified_member_list?: any[] }) {
|
|
928
|
+
async modDocMemberNotifiedScope(params) {
|
|
1026
929
|
const { agent, docId, notified_scope_type, notified_member_list } = params;
|
|
1027
930
|
const json = await this.postWecomDocApi({
|
|
1028
931
|
path: "/cgi-bin/wedoc/mod_doc_member_notified_scope",
|
|
@@ -1032,106 +935,88 @@ export class WecomDocClient {
|
|
|
1032
935
|
});
|
|
1033
936
|
return json;
|
|
1034
937
|
}
|
|
1035
|
-
|
|
1036
|
-
async editSheetData(params: {
|
|
1037
|
-
agent: ResolvedAgentAccount;
|
|
1038
|
-
docId: string;
|
|
1039
|
-
sheetId: string;
|
|
1040
|
-
startRow?: number;
|
|
1041
|
-
startColumn?: number;
|
|
1042
|
-
gridData?: any;
|
|
1043
|
-
requests?: any[]; // For direct batch_update with multiple operations
|
|
1044
|
-
}) {
|
|
938
|
+
async editSheetData(params) {
|
|
1045
939
|
const { agent, docId, sheetId, startRow = 0, startColumn = 0, gridData, requests } = params;
|
|
1046
|
-
|
|
1047
940
|
// Validate required docId
|
|
1048
941
|
const normalizedDocId = readString(docId);
|
|
1049
942
|
if (!normalizedDocId) {
|
|
1050
943
|
throw new Error('docId is required');
|
|
1051
944
|
}
|
|
1052
|
-
|
|
1053
945
|
// Validate required sheetId
|
|
1054
946
|
const normalizedSheetId = readString(sheetId);
|
|
1055
947
|
if (!normalizedSheetId) {
|
|
1056
948
|
throw new Error('sheetId is required');
|
|
1057
949
|
}
|
|
1058
|
-
|
|
1059
950
|
// Handle direct requests (for multiple operations)
|
|
1060
951
|
if (requests && requests.length > 0) {
|
|
1061
952
|
// Official API limit: ≤5 operations per batch
|
|
1062
953
|
const MAX_OPERATIONS = 5;
|
|
1063
|
-
|
|
1064
954
|
// Validate each request
|
|
1065
|
-
requests.forEach((req
|
|
955
|
+
requests.forEach((req, index) => {
|
|
1066
956
|
if (req.update_range_request?.grid_data?.rows) {
|
|
1067
957
|
const rows = req.update_range_request.grid_data.rows;
|
|
1068
958
|
const rowCount = rows.length;
|
|
1069
|
-
const rowWidths = rows.map((row
|
|
959
|
+
const rowWidths = rows.map((row) => row.values?.length || 0);
|
|
1070
960
|
const columnCount = rowWidths.length > 0 ? Math.max(...rowWidths) : 0;
|
|
1071
|
-
const totalCells = rowWidths.reduce((sum
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
if (columnCount > 200)
|
|
1075
|
-
|
|
961
|
+
const totalCells = rowWidths.reduce((sum, width) => sum + width, 0);
|
|
962
|
+
if (rowCount > 1000)
|
|
963
|
+
throw new Error(`第${index + 1}个操作:行数不能超过 1000`);
|
|
964
|
+
if (columnCount > 200)
|
|
965
|
+
throw new Error(`第${index + 1}个操作:列数不能超过 200`);
|
|
966
|
+
if (totalCells > 10000)
|
|
967
|
+
throw new Error(`第${index + 1}个操作:单元格总数不能超过 10000`);
|
|
1076
968
|
}
|
|
1077
969
|
});
|
|
1078
|
-
|
|
1079
970
|
if (requests.length > MAX_OPERATIONS) {
|
|
1080
971
|
throw new Error(`单次批量更新最多${MAX_OPERATIONS}个操作,当前:${requests.length}`);
|
|
1081
972
|
}
|
|
1082
|
-
|
|
1083
973
|
const body = {
|
|
1084
974
|
docid: normalizedDocId,
|
|
1085
975
|
requests: requests
|
|
1086
976
|
};
|
|
1087
|
-
|
|
1088
977
|
const json = await this.postWecomDocApi({
|
|
1089
978
|
path: "/cgi-bin/wedoc/spreadsheet/batch_update",
|
|
1090
979
|
actionLabel: "spreadsheet_batch_update",
|
|
1091
980
|
agent, body,
|
|
1092
981
|
});
|
|
1093
|
-
return {
|
|
1094
|
-
raw: json,
|
|
982
|
+
return {
|
|
983
|
+
raw: json,
|
|
1095
984
|
docId: normalizedDocId,
|
|
1096
985
|
operations: requests.length
|
|
1097
986
|
};
|
|
1098
987
|
}
|
|
1099
|
-
|
|
1100
988
|
// Handle single gridData update
|
|
1101
989
|
if (!gridData) {
|
|
1102
990
|
throw new Error('gridData or requests is required');
|
|
1103
991
|
}
|
|
1104
|
-
|
|
1105
992
|
// Build GridData per official API
|
|
1106
993
|
// gridData.rows[i].values[j] must be: {cell_value: {text} | {link: {text, url}}, cell_format?: {...}}
|
|
1107
|
-
const rows = (gridData.rows || []).map((row
|
|
1108
|
-
values: (row.values || []).map((cell
|
|
994
|
+
const rows = (gridData.rows || []).map((row) => ({
|
|
995
|
+
values: (row.values || []).map((cell) => {
|
|
1109
996
|
// If already CellData format, use as-is
|
|
1110
997
|
if (cell && typeof cell === 'object' && cell.cell_value) {
|
|
1111
998
|
return cell;
|
|
1112
999
|
}
|
|
1113
1000
|
// Support link simplified format: { url: '...', text: '...' }
|
|
1114
1001
|
if (cell && typeof cell === 'object' && cell.url) {
|
|
1115
|
-
return {
|
|
1116
|
-
cell_value: {
|
|
1117
|
-
link: {
|
|
1118
|
-
url: String(cell.url),
|
|
1119
|
-
text: String(cell.text ?? cell.url)
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1002
|
+
return {
|
|
1003
|
+
cell_value: {
|
|
1004
|
+
link: {
|
|
1005
|
+
url: String(cell.url),
|
|
1006
|
+
text: String(cell.text ?? cell.url)
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1122
1009
|
};
|
|
1123
1010
|
}
|
|
1124
1011
|
// Otherwise wrap primitive as CellValue with text
|
|
1125
1012
|
return { cell_value: { text: String(cell ?? '') } };
|
|
1126
1013
|
})
|
|
1127
1014
|
}));
|
|
1128
|
-
|
|
1129
1015
|
// Validate range limits per API spec
|
|
1130
1016
|
const rowCount = rows.length;
|
|
1131
|
-
const rowWidths = rows.map((row
|
|
1017
|
+
const rowWidths = rows.map((row) => row.values?.length || 0);
|
|
1132
1018
|
const columnCount = rowWidths.length > 0 ? Math.max(...rowWidths) : 0;
|
|
1133
|
-
const totalCells = rowWidths.reduce((sum
|
|
1134
|
-
|
|
1019
|
+
const totalCells = rowWidths.reduce((sum, width) => sum + width, 0);
|
|
1135
1020
|
if (rowCount > 1000) {
|
|
1136
1021
|
throw new Error(`行数不能超过 1000,当前:${rowCount}`);
|
|
1137
1022
|
}
|
|
@@ -1141,42 +1026,37 @@ export class WecomDocClient {
|
|
|
1141
1026
|
if (totalCells > 10000) {
|
|
1142
1027
|
throw new Error(`单元格总数不能超过 10000,当前:${totalCells}`);
|
|
1143
1028
|
}
|
|
1144
|
-
|
|
1145
1029
|
const finalGridData = {
|
|
1146
1030
|
start_row: startRow,
|
|
1147
1031
|
start_column: startColumn,
|
|
1148
1032
|
rows: rows
|
|
1149
1033
|
};
|
|
1150
|
-
|
|
1151
1034
|
// Build batch_update request per official API (single operation)
|
|
1152
1035
|
const body = {
|
|
1153
1036
|
docid: normalizedDocId,
|
|
1154
1037
|
requests: [{
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1038
|
+
update_range_request: {
|
|
1039
|
+
sheet_id: normalizedSheetId,
|
|
1040
|
+
grid_data: finalGridData
|
|
1041
|
+
}
|
|
1042
|
+
}]
|
|
1160
1043
|
};
|
|
1161
|
-
|
|
1162
1044
|
const json = await this.postWecomDocApi({
|
|
1163
1045
|
path: "/cgi-bin/wedoc/spreadsheet/batch_update",
|
|
1164
1046
|
actionLabel: "spreadsheet_batch_update",
|
|
1165
1047
|
agent, body,
|
|
1166
1048
|
});
|
|
1167
|
-
return {
|
|
1168
|
-
raw: json,
|
|
1049
|
+
return {
|
|
1050
|
+
raw: json,
|
|
1169
1051
|
docId: normalizedDocId,
|
|
1170
1052
|
updatedCells: json.data?.responses?.[0]?.update_range_response?.updated_cells || 0
|
|
1171
1053
|
};
|
|
1172
1054
|
}
|
|
1173
|
-
|
|
1174
1055
|
/**
|
|
1175
1056
|
* Build CellFormat object per official API
|
|
1176
1057
|
*/
|
|
1177
|
-
|
|
1178
|
-
const textFormat
|
|
1179
|
-
|
|
1058
|
+
buildCellFormat(formatData) {
|
|
1059
|
+
const textFormat = {};
|
|
1180
1060
|
// Font properties
|
|
1181
1061
|
if (formatData.font != null) {
|
|
1182
1062
|
textFormat.font = String(formatData.font);
|
|
@@ -1196,7 +1076,6 @@ export class WecomDocClient {
|
|
|
1196
1076
|
if (formatData.underline != null) {
|
|
1197
1077
|
textFormat.underline = Boolean(formatData.underline);
|
|
1198
1078
|
}
|
|
1199
|
-
|
|
1200
1079
|
// Color (RGBA)
|
|
1201
1080
|
if (formatData.color != null && typeof formatData.color === "object") {
|
|
1202
1081
|
const color = formatData.color;
|
|
@@ -1207,16 +1086,13 @@ export class WecomDocClient {
|
|
|
1207
1086
|
alpha: Math.min(255, Math.max(0, Number(color.alpha ?? 255)))
|
|
1208
1087
|
};
|
|
1209
1088
|
}
|
|
1210
|
-
|
|
1211
1089
|
// Return empty object if no format properties
|
|
1212
1090
|
if (Object.keys(textFormat).length === 0) {
|
|
1213
1091
|
return null;
|
|
1214
1092
|
}
|
|
1215
|
-
|
|
1216
1093
|
return { text_format: textFormat };
|
|
1217
1094
|
}
|
|
1218
|
-
|
|
1219
|
-
async getSheetData(params: { agent: ResolvedAgentAccount; docId: string; sheetId: string; range: string }) {
|
|
1095
|
+
async getSheetData(params) {
|
|
1220
1096
|
const { agent, docId, sheetId, range } = params;
|
|
1221
1097
|
const body = { docid: readString(docId), sheet_id: readString(sheetId), range: readString(range) };
|
|
1222
1098
|
const json = await this.postWecomDocApi({
|
|
@@ -1226,8 +1102,7 @@ export class WecomDocClient {
|
|
|
1226
1102
|
});
|
|
1227
1103
|
return { raw: json, data: json };
|
|
1228
1104
|
}
|
|
1229
|
-
|
|
1230
|
-
async modifySheetProperties(params: { agent: ResolvedAgentAccount; docId: string; requests: unknown[] }) {
|
|
1105
|
+
async modifySheetProperties(params) {
|
|
1231
1106
|
const { agent, docId, requests } = params;
|
|
1232
1107
|
const json = await this.postWecomDocApi({
|
|
1233
1108
|
path: "/cgi-bin/wedoc/spreadsheet/batch_update",
|
|
@@ -1236,10 +1111,8 @@ export class WecomDocClient {
|
|
|
1236
1111
|
});
|
|
1237
1112
|
return { raw: json, docId: docId };
|
|
1238
1113
|
}
|
|
1239
|
-
|
|
1240
1114
|
// --- Smart Table Operations ---
|
|
1241
|
-
|
|
1242
|
-
async smartTableOperate(params: { agent: ResolvedAgentAccount; docId: string; operation: string; bodyData: any }) {
|
|
1115
|
+
async smartTableOperate(params) {
|
|
1243
1116
|
const { agent, docId, operation, bodyData } = params;
|
|
1244
1117
|
const body = { docid: readString(docId), ...readObject(bodyData) };
|
|
1245
1118
|
const path = `/cgi-bin/wedoc/smartsheet/${operation}`;
|
|
@@ -1250,14 +1123,15 @@ export class WecomDocClient {
|
|
|
1250
1123
|
});
|
|
1251
1124
|
return { raw: json, docId };
|
|
1252
1125
|
}
|
|
1253
|
-
|
|
1254
|
-
async smartTableGetSheets(params: { agent: ResolvedAgentAccount; docId: string; sheet_id?: string; need_all_type_sheet?: boolean }) {
|
|
1126
|
+
async smartTableGetSheets(params) {
|
|
1255
1127
|
const { agent, docId, sheet_id, need_all_type_sheet } = params;
|
|
1256
|
-
const payload
|
|
1128
|
+
const payload = {
|
|
1257
1129
|
docid: readString(docId),
|
|
1258
1130
|
};
|
|
1259
|
-
if (sheet_id)
|
|
1260
|
-
|
|
1131
|
+
if (sheet_id)
|
|
1132
|
+
payload.sheet_id = sheet_id;
|
|
1133
|
+
if (need_all_type_sheet !== undefined)
|
|
1134
|
+
payload.need_all_type_sheet = need_all_type_sheet;
|
|
1261
1135
|
const json = await this.postWecomDocApi({
|
|
1262
1136
|
path: "/cgi-bin/wedoc/smartsheet/get_sheet",
|
|
1263
1137
|
actionLabel: "smartsheet_get_sheet",
|
|
@@ -1269,33 +1143,21 @@ export class WecomDocClient {
|
|
|
1269
1143
|
sheets: readArray(json.sheet_list),
|
|
1270
1144
|
};
|
|
1271
1145
|
}
|
|
1272
|
-
|
|
1273
|
-
async smartTableAddSheet(params: { agent: ResolvedAgentAccount; docId: string; title: string; index?: number }) {
|
|
1146
|
+
async smartTableAddSheet(params) {
|
|
1274
1147
|
const { agent, docId, title, index } = params;
|
|
1275
1148
|
return this.smartTableOperate({ agent, docId, operation: "add_sheet", bodyData: { properties: { title, index } } });
|
|
1276
1149
|
}
|
|
1277
|
-
|
|
1278
|
-
async smartTableDelSheet(params: { agent: ResolvedAgentAccount; docId: string; sheetId: string }) {
|
|
1150
|
+
async smartTableDelSheet(params) {
|
|
1279
1151
|
const { agent, docId, sheetId } = params;
|
|
1280
1152
|
return this.smartTableOperate({ agent, docId, operation: "delete_sheet", bodyData: { sheet_id: sheetId } });
|
|
1281
1153
|
}
|
|
1282
|
-
|
|
1283
|
-
async smartTableUpdateSheet(params: { agent: ResolvedAgentAccount; docId: string; sheetId: string; title: string }) {
|
|
1154
|
+
async smartTableUpdateSheet(params) {
|
|
1284
1155
|
const { agent, docId, sheetId, title } = params;
|
|
1285
1156
|
return this.smartTableOperate({ agent, docId, operation: "update_sheet", bodyData: { properties: { sheet_id: sheetId, title } } });
|
|
1286
1157
|
}
|
|
1287
|
-
async smartTableAddView(params
|
|
1288
|
-
agent: ResolvedAgentAccount;
|
|
1289
|
-
docId: string;
|
|
1290
|
-
sheetId: string;
|
|
1291
|
-
view_title: string;
|
|
1292
|
-
view_type: string;
|
|
1293
|
-
property?: any; // ViewProperty: sort_spec, filter_spec, group_spec, etc.
|
|
1294
|
-
property_gantt?: any; // Deprecated, use property instead
|
|
1295
|
-
property_calendar?: any; // Deprecated, use property instead
|
|
1296
|
-
}) {
|
|
1158
|
+
async smartTableAddView(params) {
|
|
1297
1159
|
const { agent, docId, sheetId, view_title, view_type, property, property_gantt, property_calendar } = params;
|
|
1298
|
-
const payload
|
|
1160
|
+
const payload = {
|
|
1299
1161
|
docid: readString(docId),
|
|
1300
1162
|
sheet_id: readString(sheetId),
|
|
1301
1163
|
view_title: readString(view_title),
|
|
@@ -1305,9 +1167,10 @@ export class WecomDocClient {
|
|
|
1305
1167
|
payload.property = property;
|
|
1306
1168
|
}
|
|
1307
1169
|
// Support deprecated property_gantt/property_calendar for backward compatibility
|
|
1308
|
-
if (property_gantt)
|
|
1309
|
-
|
|
1310
|
-
|
|
1170
|
+
if (property_gantt)
|
|
1171
|
+
payload.property_gantt = property_gantt;
|
|
1172
|
+
if (property_calendar)
|
|
1173
|
+
payload.property_calendar = property_calendar;
|
|
1311
1174
|
const json = await this.postWecomDocApi({
|
|
1312
1175
|
path: "/cgi-bin/wedoc/smartsheet/add_view",
|
|
1313
1176
|
actionLabel: "smartsheet_add_view",
|
|
@@ -1319,31 +1182,23 @@ export class WecomDocClient {
|
|
|
1319
1182
|
view: json.view,
|
|
1320
1183
|
};
|
|
1321
1184
|
}
|
|
1322
|
-
|
|
1323
|
-
async smartTableUpdateView(params: {
|
|
1324
|
-
agent: ResolvedAgentAccount;
|
|
1325
|
-
docId: string;
|
|
1326
|
-
sheetId: string;
|
|
1327
|
-
view_id: string;
|
|
1328
|
-
view_title?: string;
|
|
1329
|
-
property?: any; // ViewProperty: sort_spec, filter_spec, group_spec, etc.
|
|
1330
|
-
property_gantt?: any; // Deprecated, use property instead
|
|
1331
|
-
property_calendar?: any; // Deprecated, use property instead
|
|
1332
|
-
}) {
|
|
1185
|
+
async smartTableUpdateView(params) {
|
|
1333
1186
|
const { agent, docId, sheetId, view_id, view_title, property, property_gantt, property_calendar } = params;
|
|
1334
|
-
const payload
|
|
1187
|
+
const payload = {
|
|
1335
1188
|
docid: readString(docId),
|
|
1336
1189
|
sheet_id: readString(sheetId),
|
|
1337
1190
|
view_id: readString(view_id),
|
|
1338
1191
|
};
|
|
1339
|
-
if (view_title)
|
|
1192
|
+
if (view_title)
|
|
1193
|
+
payload.view_title = readString(view_title);
|
|
1340
1194
|
if (property && typeof property === 'object') {
|
|
1341
1195
|
payload.property = property;
|
|
1342
1196
|
}
|
|
1343
1197
|
// Support deprecated property_gantt/property_calendar for backward compatibility
|
|
1344
|
-
if (property_gantt)
|
|
1345
|
-
|
|
1346
|
-
|
|
1198
|
+
if (property_gantt)
|
|
1199
|
+
payload.property_gantt = property_gantt;
|
|
1200
|
+
if (property_calendar)
|
|
1201
|
+
payload.property_calendar = property_calendar;
|
|
1347
1202
|
const json = await this.postWecomDocApi({
|
|
1348
1203
|
path: "/cgi-bin/wedoc/smartsheet/update_view",
|
|
1349
1204
|
actionLabel: "smartsheet_update_view",
|
|
@@ -1355,14 +1210,11 @@ export class WecomDocClient {
|
|
|
1355
1210
|
view: json.view,
|
|
1356
1211
|
};
|
|
1357
1212
|
}
|
|
1358
|
-
|
|
1359
|
-
async smartTableDelView(params: { agent: ResolvedAgentAccount; docId: string; sheetId: string; view_ids: string[] }) {
|
|
1213
|
+
async smartTableDelView(params) {
|
|
1360
1214
|
const { agent, docId, sheetId, view_ids } = params;
|
|
1361
|
-
|
|
1362
1215
|
if (!Array.isArray(view_ids) || view_ids.length === 0) {
|
|
1363
1216
|
throw new Error("view_ids 必须是非空数组");
|
|
1364
1217
|
}
|
|
1365
|
-
|
|
1366
1218
|
return this.postWecomDocApi({
|
|
1367
1219
|
path: "/cgi-bin/wedoc/smartsheet/delete_views",
|
|
1368
1220
|
actionLabel: "smartsheet_del_view",
|
|
@@ -1374,24 +1226,18 @@ export class WecomDocClient {
|
|
|
1374
1226
|
},
|
|
1375
1227
|
});
|
|
1376
1228
|
}
|
|
1377
|
-
|
|
1378
|
-
async smartTableGetViews(params: {
|
|
1379
|
-
agent: ResolvedAgentAccount;
|
|
1380
|
-
docId: string;
|
|
1381
|
-
sheetId: string;
|
|
1382
|
-
view_ids?: string[];
|
|
1383
|
-
offset?: number;
|
|
1384
|
-
limit?: number;
|
|
1385
|
-
}) {
|
|
1229
|
+
async smartTableGetViews(params) {
|
|
1386
1230
|
const { agent, docId, sheetId, view_ids, offset, limit } = params;
|
|
1387
|
-
const payload
|
|
1231
|
+
const payload = {
|
|
1388
1232
|
docid: readString(docId),
|
|
1389
1233
|
sheet_id: readString(sheetId),
|
|
1390
1234
|
};
|
|
1391
|
-
if (view_ids && Array.isArray(view_ids))
|
|
1392
|
-
|
|
1393
|
-
if (
|
|
1394
|
-
|
|
1235
|
+
if (view_ids && Array.isArray(view_ids))
|
|
1236
|
+
payload.view_ids = view_ids;
|
|
1237
|
+
if (offset !== undefined)
|
|
1238
|
+
payload.offset = offset;
|
|
1239
|
+
if (limit !== undefined)
|
|
1240
|
+
payload.limit = limit;
|
|
1395
1241
|
const json = await this.postWecomDocApi({
|
|
1396
1242
|
path: "/cgi-bin/wedoc/smartsheet/get_views",
|
|
1397
1243
|
actionLabel: "smartsheet_get_views",
|
|
@@ -1406,23 +1252,14 @@ export class WecomDocClient {
|
|
|
1406
1252
|
next: json.next,
|
|
1407
1253
|
};
|
|
1408
1254
|
}
|
|
1409
|
-
|
|
1410
|
-
async smartTableAddFields(params: {
|
|
1411
|
-
agent: ResolvedAgentAccount;
|
|
1412
|
-
docId: string;
|
|
1413
|
-
sheetId: string;
|
|
1414
|
-
fields: any[];
|
|
1415
|
-
autoCleanupDefaultField?: boolean; // Auto-delete leftover default field after adding new fields
|
|
1416
|
-
}) {
|
|
1255
|
+
async smartTableAddFields(params) {
|
|
1417
1256
|
const { agent, docId, sheetId, fields, autoCleanupDefaultField = true } = params;
|
|
1418
|
-
|
|
1419
1257
|
// Validate fields per official API spec
|
|
1420
1258
|
if (!Array.isArray(fields) || fields.length === 0) {
|
|
1421
1259
|
throw new Error("fields 必须是非空数组");
|
|
1422
1260
|
}
|
|
1423
|
-
|
|
1424
1261
|
// Validate each field has required field_title and field_type
|
|
1425
|
-
fields.forEach((field
|
|
1262
|
+
fields.forEach((field, index) => {
|
|
1426
1263
|
if (!field.field_title) {
|
|
1427
1264
|
throw new Error(`第${index + 1}个字段:field_title 必填`);
|
|
1428
1265
|
}
|
|
@@ -1444,7 +1281,6 @@ export class WecomDocClient {
|
|
|
1444
1281
|
throw new Error(`第${index + 1}个字段:field_type 必须是有效的字段类型(见 FieldType 枚举)`);
|
|
1445
1282
|
}
|
|
1446
1283
|
});
|
|
1447
|
-
|
|
1448
1284
|
const json = await this.postWecomDocApi({
|
|
1449
1285
|
path: "/cgi-bin/wedoc/smartsheet/add_fields",
|
|
1450
1286
|
actionLabel: "smartsheet_add_fields",
|
|
@@ -1455,38 +1291,27 @@ export class WecomDocClient {
|
|
|
1455
1291
|
fields: fields,
|
|
1456
1292
|
},
|
|
1457
1293
|
});
|
|
1458
|
-
|
|
1459
1294
|
const result = {
|
|
1460
1295
|
raw: json,
|
|
1461
1296
|
fields: readArray(json.fields),
|
|
1462
1297
|
};
|
|
1463
|
-
|
|
1464
1298
|
// Auto-cleanup: delete leftover default field after successfully adding new fields
|
|
1465
1299
|
// This handles the case where initializeSmartTable kept 1 default field
|
|
1466
1300
|
if (autoCleanupDefaultField) {
|
|
1467
1301
|
await this.cleanupLeftoverDefaultField({ agent, docId, sheetId, newlyAddedFieldCount: result.fields.length });
|
|
1468
1302
|
}
|
|
1469
|
-
|
|
1470
1303
|
return result;
|
|
1471
1304
|
}
|
|
1472
|
-
|
|
1473
1305
|
/**
|
|
1474
1306
|
* Cleanup leftover default field after adding new fields
|
|
1475
1307
|
* When user adds new fields, we can safely delete the leftover default field from initialization
|
|
1476
1308
|
*/
|
|
1477
|
-
|
|
1478
|
-
agent: ResolvedAgentAccount;
|
|
1479
|
-
docId: string;
|
|
1480
|
-
sheetId: string;
|
|
1481
|
-
newlyAddedFieldCount: number;
|
|
1482
|
-
}) {
|
|
1309
|
+
async cleanupLeftoverDefaultField(params) {
|
|
1483
1310
|
const { agent, docId, sheetId, newlyAddedFieldCount } = params;
|
|
1484
|
-
|
|
1485
1311
|
try {
|
|
1486
1312
|
// Get all fields to find the leftover default field
|
|
1487
1313
|
const fieldsResult = await this.smartTableGetFields({ agent, docId, sheetId, limit: 100 });
|
|
1488
1314
|
const allFields = fieldsResult.fields || [];
|
|
1489
|
-
|
|
1490
1315
|
// After adding N new fields to a table with 1 default field, we should have N+1 fields
|
|
1491
1316
|
// If total = newlyAdded + 1, then there's 1 leftover default field to delete
|
|
1492
1317
|
if (allFields.length === newlyAddedFieldCount + 1 && newlyAddedFieldCount > 0) {
|
|
@@ -1494,38 +1319,29 @@ export class WecomDocClient {
|
|
|
1494
1319
|
// Default fields typically have generic titles like "文本", "数字", "日期", "单选", "人员"
|
|
1495
1320
|
const defaultFieldTitles = ['文本', '数字', '日期', '单选', '人员', '文本 1', '数字 1', '日期 1', '单选 1', '人员 1'];
|
|
1496
1321
|
const defaultFieldTypes = ['FIELD_TYPE_TEXT', 'FIELD_TYPE_NUMBER', 'FIELD_TYPE_DATE_TIME', 'FIELD_TYPE_SINGLE_SELECT', 'FIELD_TYPE_USER'];
|
|
1497
|
-
|
|
1498
|
-
const leftoverField = allFields.find((field: any) => {
|
|
1322
|
+
const leftoverField = allFields.find((field) => {
|
|
1499
1323
|
const isDefaultTitle = defaultFieldTitles.includes(field.field_title);
|
|
1500
1324
|
const isDefaultType = defaultFieldTypes.includes(field.field_type);
|
|
1501
1325
|
return isDefaultTitle && isDefaultType;
|
|
1502
|
-
})
|
|
1503
|
-
|
|
1326
|
+
});
|
|
1504
1327
|
if (leftoverField && leftoverField.field_id) {
|
|
1505
1328
|
await this.smartTableDelFields({ agent, docId, sheetId, field_ids: [leftoverField.field_id] });
|
|
1506
1329
|
}
|
|
1507
1330
|
}
|
|
1508
|
-
}
|
|
1331
|
+
}
|
|
1332
|
+
catch (err) {
|
|
1509
1333
|
// Non-fatal: new fields added, just cleanup failed
|
|
1510
1334
|
console.error(`[WecomDocClient] cleanupLeftoverDefaultField failed:`, err);
|
|
1511
1335
|
}
|
|
1512
1336
|
}
|
|
1513
|
-
|
|
1514
|
-
async smartTableUpdateFields(params: {
|
|
1515
|
-
agent: ResolvedAgentAccount;
|
|
1516
|
-
docId: string;
|
|
1517
|
-
sheetId: string;
|
|
1518
|
-
fields: any[];
|
|
1519
|
-
}) {
|
|
1337
|
+
async smartTableUpdateFields(params) {
|
|
1520
1338
|
const { agent, docId, sheetId, fields } = params;
|
|
1521
|
-
|
|
1522
1339
|
// Validate fields per official API spec
|
|
1523
1340
|
if (!Array.isArray(fields) || fields.length === 0) {
|
|
1524
1341
|
throw new Error("fields 必须是非空数组");
|
|
1525
1342
|
}
|
|
1526
|
-
|
|
1527
1343
|
// Validate each field has required field_id and field_type
|
|
1528
|
-
fields.forEach((field
|
|
1344
|
+
fields.forEach((field, index) => {
|
|
1529
1345
|
if (!field.field_id) {
|
|
1530
1346
|
throw new Error(`第${index + 1}个字段:field_id 必填`);
|
|
1531
1347
|
}
|
|
@@ -1537,7 +1353,6 @@ export class WecomDocClient {
|
|
|
1537
1353
|
throw new Error(`第${index + 1}个字段:field_title 或 property_* 属性至少提供一个`);
|
|
1538
1354
|
}
|
|
1539
1355
|
});
|
|
1540
|
-
|
|
1541
1356
|
const json = await this.postWecomDocApi({
|
|
1542
1357
|
path: "/cgi-bin/wedoc/smartsheet/update_fields",
|
|
1543
1358
|
actionLabel: "smartsheet_update_fields",
|
|
@@ -1553,14 +1368,11 @@ export class WecomDocClient {
|
|
|
1553
1368
|
fields: readArray(json.fields),
|
|
1554
1369
|
};
|
|
1555
1370
|
}
|
|
1556
|
-
|
|
1557
|
-
async smartTableDelFields(params: { agent: ResolvedAgentAccount; docId: string; sheetId: string; field_ids: string[] }) {
|
|
1371
|
+
async smartTableDelFields(params) {
|
|
1558
1372
|
const { agent, docId, sheetId, field_ids } = params;
|
|
1559
|
-
|
|
1560
1373
|
if (!Array.isArray(field_ids) || field_ids.length === 0) {
|
|
1561
1374
|
throw new Error("field_ids 必须是非空数组");
|
|
1562
1375
|
}
|
|
1563
|
-
|
|
1564
1376
|
return this.postWecomDocApi({
|
|
1565
1377
|
path: "/cgi-bin/wedoc/smartsheet/delete_fields",
|
|
1566
1378
|
actionLabel: "smartsheet_del_fields",
|
|
@@ -1572,28 +1384,22 @@ export class WecomDocClient {
|
|
|
1572
1384
|
},
|
|
1573
1385
|
});
|
|
1574
1386
|
}
|
|
1575
|
-
|
|
1576
|
-
async smartTableGetFields(params: {
|
|
1577
|
-
agent: ResolvedAgentAccount;
|
|
1578
|
-
docId: string;
|
|
1579
|
-
sheetId: string;
|
|
1580
|
-
view_id?: string;
|
|
1581
|
-
field_ids?: string[];
|
|
1582
|
-
field_titles?: string[];
|
|
1583
|
-
offset?: number;
|
|
1584
|
-
limit?: number;
|
|
1585
|
-
}) {
|
|
1387
|
+
async smartTableGetFields(params) {
|
|
1586
1388
|
const { agent, docId, sheetId, view_id, field_ids, field_titles, offset, limit } = params;
|
|
1587
|
-
const payload
|
|
1389
|
+
const payload = {
|
|
1588
1390
|
docid: readString(docId),
|
|
1589
1391
|
sheet_id: readString(sheetId),
|
|
1590
1392
|
};
|
|
1591
|
-
if (view_id)
|
|
1592
|
-
|
|
1593
|
-
if (
|
|
1594
|
-
|
|
1595
|
-
if (
|
|
1596
|
-
|
|
1393
|
+
if (view_id)
|
|
1394
|
+
payload.view_id = view_id;
|
|
1395
|
+
if (field_ids && Array.isArray(field_ids))
|
|
1396
|
+
payload.field_ids = field_ids;
|
|
1397
|
+
if (field_titles && Array.isArray(field_titles))
|
|
1398
|
+
payload.field_titles = field_titles;
|
|
1399
|
+
if (offset !== undefined)
|
|
1400
|
+
payload.offset = offset;
|
|
1401
|
+
if (limit !== undefined)
|
|
1402
|
+
payload.limit = limit;
|
|
1597
1403
|
const json = await this.postWecomDocApi({
|
|
1598
1404
|
path: "/cgi-bin/wedoc/smartsheet/get_fields",
|
|
1599
1405
|
actionLabel: "smartsheet_get_fields",
|
|
@@ -1608,192 +1414,162 @@ export class WecomDocClient {
|
|
|
1608
1414
|
next: json.next,
|
|
1609
1415
|
};
|
|
1610
1416
|
}
|
|
1611
|
-
|
|
1612
|
-
async smartTableAddGroup(params: { agent: ResolvedAgentAccount; docId: string; sheetId: string; name: string; children?: string[] }) {
|
|
1417
|
+
async smartTableAddGroup(params) {
|
|
1613
1418
|
const { agent, docId, sheetId, name, children } = params;
|
|
1614
1419
|
return this.smartTableOperate({ agent, docId, operation: "add_field_group", bodyData: { sheet_id: sheetId, name, children } });
|
|
1615
1420
|
}
|
|
1616
|
-
|
|
1617
|
-
async smartTableDelGroup(params: { agent: ResolvedAgentAccount; docId: string; sheetId: string; field_group_id: string }) {
|
|
1421
|
+
async smartTableDelGroup(params) {
|
|
1618
1422
|
const { agent, docId, sheetId, field_group_id } = params;
|
|
1619
1423
|
return this.smartTableOperate({ agent, docId, operation: "delete_field_group", bodyData: { sheet_id: sheetId, field_group_id } });
|
|
1620
1424
|
}
|
|
1621
|
-
|
|
1622
|
-
async smartTableUpdateGroup(params: { agent: ResolvedAgentAccount; docId: string; sheetId: string; field_group_id: string; name?: string; children?: string[] }) {
|
|
1425
|
+
async smartTableUpdateGroup(params) {
|
|
1623
1426
|
const { agent, docId, sheetId, field_group_id, name, children } = params;
|
|
1624
1427
|
return this.smartTableOperate({ agent, docId, operation: "update_field_group", bodyData: { sheet_id: sheetId, field_group_id, name, children } });
|
|
1625
1428
|
}
|
|
1626
|
-
|
|
1627
|
-
async smartTableGetGroups(params: { agent: ResolvedAgentAccount; docId: string; sheetId: string }) {
|
|
1429
|
+
async smartTableGetGroups(params) {
|
|
1628
1430
|
const { agent, docId, sheetId } = params;
|
|
1629
1431
|
return this.smartTableOperate({ agent, docId, operation: "get_field_groups", bodyData: { sheet_id: sheetId } });
|
|
1630
1432
|
}
|
|
1631
|
-
|
|
1632
|
-
async smartTableAddExternalRecords(params: { agent: ResolvedAgentAccount; docId: string; sheetId: string; records: any[] }) {
|
|
1433
|
+
async smartTableAddExternalRecords(params) {
|
|
1633
1434
|
const { agent, docId, sheetId, records } = params;
|
|
1634
1435
|
return this.smartTableOperate({ agent, docId, operation: "add_external_records", bodyData: { sheet_id: sheetId, records } });
|
|
1635
1436
|
}
|
|
1636
|
-
|
|
1637
|
-
async smartTableUpdateExternalRecords(params: { agent: ResolvedAgentAccount; docId: string; sheetId: string; records: any[] }) {
|
|
1437
|
+
async smartTableUpdateExternalRecords(params) {
|
|
1638
1438
|
const { agent, docId, sheetId, records } = params;
|
|
1639
1439
|
return this.smartTableOperate({ agent, docId, operation: "update_external_records", bodyData: { sheet_id: sheetId, records } });
|
|
1640
1440
|
}
|
|
1641
|
-
|
|
1642
|
-
async smartTableAddRecords(params: {
|
|
1643
|
-
agent: ResolvedAgentAccount;
|
|
1644
|
-
docId: string;
|
|
1645
|
-
sheetId: string;
|
|
1646
|
-
records: any[];
|
|
1647
|
-
key_type?: string;
|
|
1648
|
-
}) {
|
|
1441
|
+
async smartTableAddRecords(params) {
|
|
1649
1442
|
const { agent, docId, sheetId, records, key_type } = params;
|
|
1650
|
-
|
|
1651
1443
|
// Validate records format per official API spec (doc2.txt line 1594-1601)
|
|
1652
1444
|
if (!Array.isArray(records) || records.length === 0) {
|
|
1653
1445
|
throw new Error("records 必须是非空数组");
|
|
1654
1446
|
}
|
|
1655
|
-
|
|
1656
1447
|
// Strict validation: require correct format based on field type
|
|
1657
1448
|
// Do NOT auto-convert ambiguous values to avoid corrupting user intent
|
|
1658
|
-
const validatedRecords = records.map((record
|
|
1449
|
+
const validatedRecords = records.map((record, recordIndex) => {
|
|
1659
1450
|
if (!record.values || typeof record.values !== 'object' || Array.isArray(record.values)) {
|
|
1660
1451
|
throw new Error(`第${recordIndex + 1}条记录:values 必须是非空对象`);
|
|
1661
1452
|
}
|
|
1662
|
-
|
|
1663
|
-
const validatedValues: Record<string, any> = {};
|
|
1453
|
+
const validatedValues = {};
|
|
1664
1454
|
for (const [key, value] of Object.entries(record.values)) {
|
|
1665
1455
|
// Accept both array and non-array formats based on field type
|
|
1666
1456
|
// Array types: TEXT, USER, SELECT, SINGLE_SELECT, CHECKBOX, PHONE_NUMBER, EMAIL, URL, LOCATION, BARCODE, ATTACHMENT, IMAGE
|
|
1667
1457
|
// Non-array types: NUMBER, DATE_TIME, PROGRESS, CURRENCY, PERCENTAGE
|
|
1668
|
-
|
|
1669
1458
|
if (Array.isArray(value)) {
|
|
1670
1459
|
// Array format - validate structure
|
|
1671
1460
|
if (value.length === 0) {
|
|
1672
1461
|
throw new Error(`第${recordIndex + 1}条记录字段 "${key}": 数组不能为空`);
|
|
1673
1462
|
}
|
|
1674
1463
|
validatedValues[key] = value;
|
|
1675
|
-
}
|
|
1464
|
+
}
|
|
1465
|
+
else if (typeof value === 'number') {
|
|
1676
1466
|
// Non-array number - valid for NUMBER, PROGRESS, CURRENCY, PERCENTAGE
|
|
1677
1467
|
validatedValues[key] = value;
|
|
1678
|
-
}
|
|
1468
|
+
}
|
|
1469
|
+
else if (typeof value === 'string' && /^\d{13}$/.test(value)) {
|
|
1679
1470
|
// Non-array 13-digit string - valid for DATE_TIME (millisecond timestamp)
|
|
1680
1471
|
validatedValues[key] = value;
|
|
1681
|
-
}
|
|
1472
|
+
}
|
|
1473
|
+
else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
1682
1474
|
// Object format - wrap in array for types like USER, TEXT object
|
|
1683
1475
|
// This allows {user_id: "..."} to become [{user_id: "..."}]
|
|
1684
1476
|
validatedValues[key] = [value];
|
|
1685
|
-
}
|
|
1477
|
+
}
|
|
1478
|
+
else {
|
|
1686
1479
|
// Reject ambiguous primitives (plain strings, booleans)
|
|
1687
1480
|
// Users should explicitly use array format: [{type: "text", text: "..."}]
|
|
1688
|
-
throw new Error(
|
|
1689
|
-
`第${recordIndex + 1}条记录字段 "${key}": 值格式不明确。` +
|
|
1481
|
+
throw new Error(`第${recordIndex + 1}条记录字段 "${key}": 值格式不明确。` +
|
|
1690
1482
|
`数字/日期类型直接写值 (25, "1704067200000"),` +
|
|
1691
|
-
`文本/成员/选项类型用数组 ([{"type": "text", "text": "..."}], [{"user_id": "..."}])`
|
|
1692
|
-
);
|
|
1483
|
+
`文本/成员/选项类型用数组 ([{"type": "text", "text": "..."}], [{"user_id": "..."}])`);
|
|
1693
1484
|
}
|
|
1694
1485
|
}
|
|
1695
|
-
|
|
1696
1486
|
return {
|
|
1697
1487
|
...record,
|
|
1698
1488
|
values: validatedValues,
|
|
1699
1489
|
};
|
|
1700
1490
|
});
|
|
1701
|
-
|
|
1702
|
-
const bodyData: Record<string, unknown> = {
|
|
1491
|
+
const bodyData = {
|
|
1703
1492
|
sheet_id: readString(sheetId),
|
|
1704
1493
|
records: validatedRecords,
|
|
1705
1494
|
};
|
|
1706
|
-
|
|
1707
1495
|
if (key_type) {
|
|
1708
1496
|
bodyData.key_type = key_type;
|
|
1709
1497
|
}
|
|
1710
|
-
|
|
1711
1498
|
return this.smartTableOperate({ agent, docId, operation: "add_records", bodyData });
|
|
1712
1499
|
}
|
|
1713
|
-
|
|
1714
|
-
async smartTableUpdateRecords(params: { agent: ResolvedAgentAccount; docId: string; sheetId: string; records: any[] }) {
|
|
1500
|
+
async smartTableUpdateRecords(params) {
|
|
1715
1501
|
const { agent, docId, sheetId, records } = params;
|
|
1716
|
-
|
|
1717
1502
|
// Strict validation: same as addRecords
|
|
1718
1503
|
if (!Array.isArray(records) || records.length === 0) {
|
|
1719
1504
|
throw new Error("records 必须是非空数组");
|
|
1720
1505
|
}
|
|
1721
|
-
|
|
1722
|
-
const validatedRecords = records.map((record: any, recordIndex: number) => {
|
|
1506
|
+
const validatedRecords = records.map((record, recordIndex) => {
|
|
1723
1507
|
if (!record.record_id) {
|
|
1724
1508
|
throw new Error(`第${recordIndex + 1}条记录缺少 record_id`);
|
|
1725
1509
|
}
|
|
1726
1510
|
if (!record.values || typeof record.values !== 'object' || Array.isArray(record.values)) {
|
|
1727
1511
|
throw new Error(`第${recordIndex + 1}条记录:values 必须是非空对象`);
|
|
1728
1512
|
}
|
|
1729
|
-
|
|
1730
|
-
const validatedValues: Record<string, any> = {};
|
|
1513
|
+
const validatedValues = {};
|
|
1731
1514
|
for (const [key, value] of Object.entries(record.values)) {
|
|
1732
1515
|
if (Array.isArray(value)) {
|
|
1733
1516
|
if (value.length === 0) {
|
|
1734
1517
|
throw new Error(`第${recordIndex + 1}条记录字段 "${key}": 数组不能为空`);
|
|
1735
1518
|
}
|
|
1736
1519
|
validatedValues[key] = value;
|
|
1737
|
-
}
|
|
1520
|
+
}
|
|
1521
|
+
else if (typeof value === 'number') {
|
|
1738
1522
|
validatedValues[key] = value;
|
|
1739
|
-
}
|
|
1523
|
+
}
|
|
1524
|
+
else if (typeof value === 'string' && /^\d{13}$/.test(value)) {
|
|
1740
1525
|
validatedValues[key] = value;
|
|
1741
|
-
}
|
|
1526
|
+
}
|
|
1527
|
+
else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
1742
1528
|
validatedValues[key] = [value];
|
|
1743
|
-
}
|
|
1744
|
-
|
|
1745
|
-
|
|
1529
|
+
}
|
|
1530
|
+
else {
|
|
1531
|
+
throw new Error(`第${recordIndex + 1}条记录字段 "${key}": 值格式不明确。` +
|
|
1746
1532
|
`数字/日期类型直接写值 (25, "1704067200000"),` +
|
|
1747
|
-
`文本/成员/选项类型用数组 ([{"type": "text", "text": "..."}], [{"user_id": "..."}])`
|
|
1748
|
-
);
|
|
1533
|
+
`文本/成员/选项类型用数组 ([{"type": "text", "text": "..."}], [{"user_id": "..."}])`);
|
|
1749
1534
|
}
|
|
1750
1535
|
}
|
|
1751
|
-
|
|
1752
1536
|
return {
|
|
1753
1537
|
...record,
|
|
1754
1538
|
values: validatedValues,
|
|
1755
1539
|
};
|
|
1756
1540
|
});
|
|
1757
|
-
|
|
1758
1541
|
return this.smartTableOperate({ agent, docId, operation: "update_records", bodyData: { sheet_id: sheetId, records: validatedRecords } });
|
|
1759
1542
|
}
|
|
1760
|
-
|
|
1761
|
-
async smartTableDelRecords(params: { agent: ResolvedAgentAccount; docId: string; sheetId: string; record_ids: string[] }) {
|
|
1543
|
+
async smartTableDelRecords(params) {
|
|
1762
1544
|
const { agent, docId, sheetId, record_ids } = params;
|
|
1763
1545
|
return this.smartTableOperate({ agent, docId, operation: "delete_records", bodyData: { sheet_id: sheetId, record_ids } });
|
|
1764
1546
|
}
|
|
1765
|
-
|
|
1766
|
-
async smartTableGetRecords(params: {
|
|
1767
|
-
agent: ResolvedAgentAccount;
|
|
1768
|
-
docId: string;
|
|
1769
|
-
sheetId: string;
|
|
1770
|
-
view_id?: string;
|
|
1771
|
-
record_ids?: string[];
|
|
1772
|
-
key_type?: string;
|
|
1773
|
-
field_titles?: string[];
|
|
1774
|
-
field_ids?: string[];
|
|
1775
|
-
sort?: any[];
|
|
1776
|
-
offset?: number;
|
|
1777
|
-
limit?: number;
|
|
1778
|
-
ver?: number;
|
|
1779
|
-
filter_spec?: any;
|
|
1780
|
-
}) {
|
|
1547
|
+
async smartTableGetRecords(params) {
|
|
1781
1548
|
const { agent, docId, sheetId, view_id, record_ids, key_type, field_titles, field_ids, sort, offset, limit, ver, filter_spec } = params;
|
|
1782
|
-
const payload
|
|
1549
|
+
const payload = {
|
|
1783
1550
|
docid: readString(docId),
|
|
1784
1551
|
sheet_id: readString(sheetId),
|
|
1785
1552
|
};
|
|
1786
|
-
if (view_id)
|
|
1787
|
-
|
|
1788
|
-
if (
|
|
1789
|
-
|
|
1790
|
-
if (
|
|
1791
|
-
|
|
1792
|
-
if (
|
|
1793
|
-
|
|
1794
|
-
if (
|
|
1795
|
-
|
|
1796
|
-
|
|
1553
|
+
if (view_id)
|
|
1554
|
+
payload.view_id = view_id;
|
|
1555
|
+
if (record_ids && Array.isArray(record_ids))
|
|
1556
|
+
payload.record_ids = record_ids;
|
|
1557
|
+
if (key_type)
|
|
1558
|
+
payload.key_type = key_type;
|
|
1559
|
+
if (field_titles && Array.isArray(field_titles))
|
|
1560
|
+
payload.field_titles = field_titles;
|
|
1561
|
+
if (field_ids && Array.isArray(field_ids))
|
|
1562
|
+
payload.field_ids = field_ids;
|
|
1563
|
+
if (sort && Array.isArray(sort))
|
|
1564
|
+
payload.sort = sort;
|
|
1565
|
+
if (offset !== undefined)
|
|
1566
|
+
payload.offset = offset;
|
|
1567
|
+
if (limit !== undefined)
|
|
1568
|
+
payload.limit = limit;
|
|
1569
|
+
if (ver !== undefined)
|
|
1570
|
+
payload.ver = ver;
|
|
1571
|
+
if (filter_spec && typeof filter_spec === 'object')
|
|
1572
|
+
payload.filter_spec = filter_spec;
|
|
1797
1573
|
const json = await this.postWecomDocApi({
|
|
1798
1574
|
path: "/cgi-bin/wedoc/smartsheet/get_records",
|
|
1799
1575
|
actionLabel: "smartsheet_get_records",
|
|
@@ -1809,10 +1585,8 @@ export class WecomDocClient {
|
|
|
1809
1585
|
ver: json.ver,
|
|
1810
1586
|
};
|
|
1811
1587
|
}
|
|
1812
|
-
|
|
1813
1588
|
// --- Smartsheet Content Permissions ---
|
|
1814
|
-
|
|
1815
|
-
async smartTableGetSheetPriv(params: { agent: ResolvedAgentAccount; docId: string; type: number; rule_id_list?: number[] }) {
|
|
1589
|
+
async smartTableGetSheetPriv(params) {
|
|
1816
1590
|
const { agent, docId, type, rule_id_list } = params;
|
|
1817
1591
|
const json = await this.postWecomDocApi({
|
|
1818
1592
|
path: "/cgi-bin/wedoc/smartsheet/content_priv/get_sheet_priv",
|
|
@@ -1822,13 +1596,13 @@ export class WecomDocClient {
|
|
|
1822
1596
|
});
|
|
1823
1597
|
return { raw: json };
|
|
1824
1598
|
}
|
|
1825
|
-
|
|
1826
|
-
async smartTableUpdateSheetPriv(params: { agent: ResolvedAgentAccount; docId: string; type: number; rule_id?: number; name?: string; priv_list: any[] }) {
|
|
1599
|
+
async smartTableUpdateSheetPriv(params) {
|
|
1827
1600
|
const { agent, docId, type, rule_id, name, priv_list } = params;
|
|
1828
|
-
const body
|
|
1829
|
-
if (rule_id !== undefined)
|
|
1830
|
-
|
|
1831
|
-
|
|
1601
|
+
const body = { docid: readString(docId), type, priv_list };
|
|
1602
|
+
if (rule_id !== undefined)
|
|
1603
|
+
body.rule_id = rule_id;
|
|
1604
|
+
if (name !== undefined)
|
|
1605
|
+
body.name = name;
|
|
1832
1606
|
const json = await this.postWecomDocApi({
|
|
1833
1607
|
path: "/cgi-bin/wedoc/smartsheet/content_priv/update_sheet_priv",
|
|
1834
1608
|
actionLabel: "smartsheet_update_sheet_priv",
|
|
@@ -1837,8 +1611,7 @@ export class WecomDocClient {
|
|
|
1837
1611
|
});
|
|
1838
1612
|
return { raw: json };
|
|
1839
1613
|
}
|
|
1840
|
-
|
|
1841
|
-
async smartTableCreateRule(params: { agent: ResolvedAgentAccount; docId: string; name: string }) {
|
|
1614
|
+
async smartTableCreateRule(params) {
|
|
1842
1615
|
const { agent, docId, name } = params;
|
|
1843
1616
|
const json = await this.postWecomDocApi({
|
|
1844
1617
|
path: "/cgi-bin/wedoc/smartsheet/content_priv/create_rule",
|
|
@@ -1848,13 +1621,13 @@ export class WecomDocClient {
|
|
|
1848
1621
|
});
|
|
1849
1622
|
return { raw: json, rule_id: json.rule_id };
|
|
1850
1623
|
}
|
|
1851
|
-
|
|
1852
|
-
async smartTableModRuleMember(params: { agent: ResolvedAgentAccount; docId: string; rule_id: number; add_member_range?: any; del_member_range?: any }) {
|
|
1624
|
+
async smartTableModRuleMember(params) {
|
|
1853
1625
|
const { agent, docId, rule_id, add_member_range, del_member_range } = params;
|
|
1854
|
-
const body
|
|
1855
|
-
if (add_member_range)
|
|
1856
|
-
|
|
1857
|
-
|
|
1626
|
+
const body = { docid: readString(docId), rule_id };
|
|
1627
|
+
if (add_member_range)
|
|
1628
|
+
body.add_member_range = add_member_range;
|
|
1629
|
+
if (del_member_range)
|
|
1630
|
+
body.del_member_range = del_member_range;
|
|
1858
1631
|
const json = await this.postWecomDocApi({
|
|
1859
1632
|
path: "/cgi-bin/wedoc/smartsheet/content_priv/mod_rule_member",
|
|
1860
1633
|
actionLabel: "smartsheet_mod_rule_member",
|
|
@@ -1863,8 +1636,7 @@ export class WecomDocClient {
|
|
|
1863
1636
|
});
|
|
1864
1637
|
return { raw: json };
|
|
1865
1638
|
}
|
|
1866
|
-
|
|
1867
|
-
async smartTableDeleteRule(params: { agent: ResolvedAgentAccount; docId: string; rule_id_list: number[] }) {
|
|
1639
|
+
async smartTableDeleteRule(params) {
|
|
1868
1640
|
const { agent, docId, rule_id_list } = params;
|
|
1869
1641
|
const json = await this.postWecomDocApi({
|
|
1870
1642
|
path: "/cgi-bin/wedoc/smartsheet/content_priv/delete_rule",
|
|
@@ -1874,10 +1646,8 @@ export class WecomDocClient {
|
|
|
1874
1646
|
});
|
|
1875
1647
|
return { raw: json };
|
|
1876
1648
|
}
|
|
1877
|
-
|
|
1878
1649
|
// --- Advanced Account Management ---
|
|
1879
|
-
|
|
1880
|
-
async assignDocAdvancedAccount(params: { agent: ResolvedAgentAccount; userid_list: string[] }) {
|
|
1650
|
+
async assignDocAdvancedAccount(params) {
|
|
1881
1651
|
const { agent, userid_list } = params;
|
|
1882
1652
|
return this.postWecomDocApi({
|
|
1883
1653
|
path: "/cgi-bin/meeting/vip/submit_batch_add_job",
|
|
@@ -1886,8 +1656,7 @@ export class WecomDocClient {
|
|
|
1886
1656
|
body: { userid_list },
|
|
1887
1657
|
});
|
|
1888
1658
|
}
|
|
1889
|
-
|
|
1890
|
-
async cancelDocAdvancedAccount(params: { agent: ResolvedAgentAccount; userid_list: string[] }) {
|
|
1659
|
+
async cancelDocAdvancedAccount(params) {
|
|
1891
1660
|
const { agent, userid_list } = params;
|
|
1892
1661
|
return this.postWecomDocApi({
|
|
1893
1662
|
path: "/cgi-bin/meeting/vip/submit_batch_del_job",
|
|
@@ -1896,8 +1665,7 @@ export class WecomDocClient {
|
|
|
1896
1665
|
body: { userid_list },
|
|
1897
1666
|
});
|
|
1898
1667
|
}
|
|
1899
|
-
|
|
1900
|
-
async getDocAdvancedAccountList(params: { agent: ResolvedAgentAccount; cursor?: number; limit?: number }) {
|
|
1668
|
+
async getDocAdvancedAccountList(params) {
|
|
1901
1669
|
const { agent, cursor, limit } = params;
|
|
1902
1670
|
return this.postWecomDocApi({
|
|
1903
1671
|
path: "/cgi-bin/meeting/vip/get_vip_user_list",
|
|
@@ -1906,14 +1674,12 @@ export class WecomDocClient {
|
|
|
1906
1674
|
body: { cursor: cursor !== undefined ? String(cursor) : undefined, limit: limit ?? 100 },
|
|
1907
1675
|
});
|
|
1908
1676
|
}
|
|
1909
|
-
|
|
1910
1677
|
// --- Material Management ---
|
|
1911
|
-
|
|
1912
|
-
async uploadDocImage(params: { agent: ResolvedAgentAccount; docId: string; base64_content: string }) {
|
|
1678
|
+
async uploadDocImage(params) {
|
|
1913
1679
|
const { agent, docId, base64_content } = params;
|
|
1914
1680
|
const normalizedDocId = readString(docId);
|
|
1915
|
-
if (!normalizedDocId)
|
|
1916
|
-
|
|
1681
|
+
if (!normalizedDocId)
|
|
1682
|
+
throw new Error("docId required");
|
|
1917
1683
|
const json = await this.postWecomDocApi({
|
|
1918
1684
|
path: "/cgi-bin/wedoc/image_upload",
|
|
1919
1685
|
actionLabel: "upload_doc_image",
|
|
@@ -1923,7 +1689,6 @@ export class WecomDocClient {
|
|
|
1923
1689
|
base64_content: base64_content
|
|
1924
1690
|
}
|
|
1925
1691
|
});
|
|
1926
|
-
|
|
1927
1692
|
return {
|
|
1928
1693
|
raw: json,
|
|
1929
1694
|
url: readString(json.url),
|