weaver-work-cli 0.1.28 → 0.1.31
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/dist/chunks/archive-U766FTFH.js +2537 -0
- package/dist/chunks/archive-oa-DMWEKX3L.js +1317 -0
- package/dist/chunks/asset-TCR7VDEV.js +2109 -0
- package/dist/chunks/attachment-content-AQNX5N3S.js +23 -0
- package/dist/chunks/blog-EVZWGDVM.js +2157 -0
- package/dist/chunks/caizhilian-JOWS6SL5.js +10087 -0
- package/dist/chunks/calendar-5WNCV66Q.js +1195 -0
- package/dist/chunks/chunk-2DUV44UX.js +15606 -0
- package/dist/chunks/chunk-324YPTC2.js +1607 -0
- package/dist/chunks/chunk-65QMVWHS.js +231 -0
- package/dist/chunks/chunk-6V7ZLF34.js +387 -0
- package/dist/chunks/chunk-AC7KJWC5.js +358 -0
- package/dist/chunks/chunk-AJ62BGAW.js +29 -0
- package/dist/chunks/chunk-BUSC6UAE.js +43 -0
- package/dist/chunks/chunk-CVZ2JOSW.js +62 -0
- package/dist/chunks/chunk-D4LTJSJD.js +477 -0
- package/dist/chunks/chunk-EG6ZU444.js +654 -0
- package/dist/chunks/chunk-EZALDOQH.js +383 -0
- package/dist/chunks/chunk-FMPJJYYI.js +106 -0
- package/dist/chunks/chunk-G2JSIUWF.js +769 -0
- package/dist/chunks/chunk-GCG2NMWR.js +703 -0
- package/dist/chunks/chunk-GPMFD4RD.js +75 -0
- package/dist/chunks/chunk-H3WDBYJW.js +508 -0
- package/dist/chunks/chunk-H6XSTSLM.js +2357 -0
- package/dist/chunks/chunk-J7RJTZSV.js +5556 -0
- package/dist/chunks/chunk-LUSPKZKY.js +53 -0
- package/dist/chunks/chunk-NIAJ5ZCG.js +73 -0
- package/dist/chunks/chunk-NOODWMCL.js +584 -0
- package/dist/chunks/chunk-OOUTBLZ4.js +51 -0
- package/dist/chunks/chunk-P26ZWSKU.js +73 -0
- package/dist/chunks/chunk-QWY6PGL6.js +3472 -0
- package/dist/chunks/chunk-R2IJAK7T.js +464 -0
- package/dist/chunks/chunk-R7O5PUWO.js +205 -0
- package/dist/chunks/chunk-RCGYCOMG.js +6962 -0
- package/dist/chunks/chunk-VZTXRG6X.js +403 -0
- package/dist/chunks/chunk-WHD4XMRP.js +161 -0
- package/dist/chunks/chunk-YLCYX7LE.js +371 -0
- package/dist/chunks/chunk-ZEDWSH32.js +68 -0
- package/dist/chunks/continuation-2CKSBLA6.js +11 -0
- package/dist/chunks/continuation-HZIZRZBX.js +13 -0
- package/dist/chunks/continuation-NLECEJPX.js +11 -0
- package/dist/chunks/ebuilder-form-NJ4YK6CC.js +2276 -0
- package/dist/chunks/ehr-MMYN36VA.js +5241 -0
- package/dist/chunks/employee-SAK2QYXX.js +11 -0
- package/dist/chunks/esb-HIWHOU7Q.js +141 -0
- package/dist/chunks/fna-KBACQTA5.js +1444 -0
- package/dist/chunks/host-3OHS5QUX.js +21 -0
- package/dist/chunks/host-IG6KEH5Q.js +19 -0
- package/dist/chunks/host-KQL5N4HO.js +23 -0
- package/dist/chunks/host-LLSZQCWR.js +17 -0
- package/dist/chunks/hrm-LYEC67ZQ.js +244 -0
- package/dist/chunks/im-RN2UKAEU.js +252 -0
- package/dist/chunks/invoice-EEPHLAF6.js +5179 -0
- package/dist/chunks/jiuchuanhui-WVVZYSJE.js +1940 -0
- package/dist/chunks/lazy-dispatch-MDOFFL2S.js +28 -0
- package/dist/chunks/mail-LNQLTF6L.js +2695 -0
- package/dist/chunks/meeting-XSD3BDVQ.js +504 -0
- package/dist/chunks/msg-parse-4GSQ2WTO.js +41 -0
- package/dist/chunks/okr-TMWTIU2K.js +2482 -0
- package/dist/chunks/plan-A2FSFA7T.js +2025 -0
- package/dist/chunks/project-T26QLBQF.js +1361 -0
- package/dist/chunks/registry-2VLUAESA.js +14 -0
- package/dist/chunks/registry-JCFEYXOE.js +18 -0
- package/dist/chunks/registry-NYPYMZXG.js +16 -0
- package/dist/chunks/registry-Q7OQJ3SU.js +19 -0
- package/dist/chunks/registry-ZJMJVWFA.js +19 -0
- package/dist/chunks/room-recommend-UR4ZDZS6.js +20 -0
- package/dist/chunks/schedule-5L2PM4M6.js +24 -0
- package/dist/chunks/state-Y2XBP6YE.js +15 -0
- package/dist/chunks/workflow-TR6PG2SL.js +245 -0
- package/dist/cmd/argv.js +45 -0
- package/dist/cmd/docs/index.js +3 -3
- package/dist/cmd/lazy-dispatch.js +20 -0
- package/dist/cmd/root.js +2 -4
- package/dist/cmd/setup/index.js +2 -2
- package/dist/cmd/skills/index.js +2 -2
- package/dist/core/package-paths.js +47 -0
- package/dist/index.js +163 -7
- package/dist/internal/e10/auth/xiaoe.js +3 -3
- package/dist/internal/e10/request-runtime.js +18 -62
- package/dist/internal/skills/detector.js +2 -2
- package/dist/shortcuts/contract/data/performance-catalog.js +1306 -0
- package/dist/shortcuts/contract/host.js +91 -35
- package/dist/shortcuts/contract/index.js +213 -0
- package/dist/shortcuts/contract/manifest.js +928 -0
- package/dist/shortcuts/contract/ooxml/docx.js +295 -0
- package/dist/shortcuts/contract/ooxml/xlsx.js +221 -0
- package/dist/shortcuts/contract/ooxml/zip.js +158 -0
- package/dist/shortcuts/contract/operations/assistant.js +1156 -0
- package/dist/shortcuts/contract/operations/clause-library.js +522 -0
- package/dist/shortcuts/contract/operations/compare.js +193 -0
- package/dist/shortcuts/contract/operations/credit-page.js +34 -0
- package/dist/shortcuts/contract/operations/flow.js +98 -0
- package/dist/shortcuts/contract/operations/page.js +66 -0
- package/dist/shortcuts/contract/operations/performance.js +733 -0
- package/dist/shortcuts/contract/operations/quote.js +557 -0
- package/dist/shortcuts/contract/operations/recommend.js +78 -0
- package/dist/shortcuts/contract/operations/registry.js +18 -0
- package/dist/shortcuts/contract/operations/review.js +83 -0
- package/dist/shortcuts/contract/operations/shared.js +37 -0
- package/dist/shortcuts/contract/operations/upload.js +108 -0
- package/dist/shortcuts/contract/operations/write.js +3 -2
- package/dist/shortcuts/index.js +140 -40
- package/dist/shortcuts/invoice/host.js +2 -1
- package/dist/shortcuts/invoice/manifest.js +36 -12
- package/dist/shortcuts/invoice/operations/issuing-qys.js +132 -36
- package/dist/shortcuts/invoice/operations/reim-auto.js +9 -0
- package/dist/shortcuts/invoice/operations/reim.js +81 -5
- package/dist/shortcuts/invoice/operations/shared.js +12 -5
- package/dist/shortcuts/meeting/host.js +45 -3
- package/dist/shortcuts/meeting/invitation/docx.js +442 -0
- package/dist/shortcuts/meeting/operations/attachment-content.js +418 -0
- package/dist/shortcuts/meeting/operations/attachment.js +442 -0
- package/dist/shortcuts/meeting/operations/eb/cache.js +57 -0
- package/dist/shortcuts/meeting/operations/eb/catalog.js +343 -28
- package/dist/shortcuts/meeting/operations/eb/conflict.js +372 -11
- package/dist/shortcuts/meeting/operations/eb/create-flow.js +710 -0
- package/dist/shortcuts/meeting/operations/eb/decision.js +47 -1
- package/dist/shortcuts/meeting/operations/eb/factory.js +129 -11
- package/dist/shortcuts/meeting/operations/eb/index.js +122 -2
- package/dist/shortcuts/meeting/operations/eb/room-recommend.js +378 -0
- package/dist/shortcuts/meeting/operations/eb/room-summary.js +84 -0
- package/dist/shortcuts/meeting/operations/eb/schedule.js +450 -0
- package/dist/shortcuts/meeting/operations/from-group-chat.js +576 -0
- package/dist/shortcuts/meeting/operations/invitation.js +458 -0
- package/dist/shortcuts/meeting/operations/minute-content.js +266 -0
- package/dist/shortcuts/meeting/operations/pipeline.js +489 -0
- package/dist/shortcuts/meeting/operations/qrcode.js +131 -0
- package/dist/shortcuts/meeting/operations/receipts.js +1 -1
- package/dist/shortcuts/meeting/operations/registry.js +18 -0
- package/dist/shortcuts/meeting/operations/summary.js +276 -0
- package/dist/shortcuts/meeting/operations/task-notify.js +325 -0
- package/dist/shortcuts/meeting/operations.js +42 -1
- package/dist/shortcuts/meeting/qr/encoder.js +427 -0
- package/dist/shortcuts/meeting/qr/render.js +103 -0
- package/dist/shortcuts/workflow/index.js +3 -0
- package/dist/shortcuts/workflow/operations/form.js +17 -5
- package/dist/shortcuts/workflow/operations/read.js +13 -6
- package/dist/shortcuts/workflow/operations/registry.js +2 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/businessRules.js +331 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/detailFieldRules.js +133 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/summaryCache.js +326 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailCache.js +113 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailFetcher.js +259 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoListRows.js +64 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoOutputPlanner.js +28 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.aggregate.js +70 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +267 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +392 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.detail.js +165 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +448 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +348 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +222 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.pipeline.js +66 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +502 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +540 -0
- package/docs/_catalog.md +1 -0
- package/docs/contract.md +39 -4
- package/docs/invoice.md +7 -7
- package/docs/todo-smart-convert/README.md +171 -0
- package/docs/todo-smart-convert/data-contract.md +236 -0
- package/docs/todo-smart-convert/mock/ai-todo-query-target.json +209 -0
- package/docs/todo-smart-convert/subgroup-rules.md +245 -0
- package/package.json +3 -2
- package/scripts/bundle.mjs +63 -0
- package/scripts/package-skill.mjs +1 -1
- package/skill-template/business-info.json +25 -4
- package/skill-template/domains/jinchengda.md +16 -3
- package/skill-template/domains/yepiaotong.md +3 -3
- package/skills/weaver-e10-jinchengda/SKILL.md +111 -31
- package/skills/weaver-e10-jinchengda/references/contract-agent-entry.md +7 -13
- package/skills/weaver-e10-jinchengda/references/contract-ai-assistant.md +150 -0
- package/skills/weaver-e10-jinchengda/references/contract-ai-review.md +87 -0
- package/skills/weaver-e10-jinchengda/references/contract-clause-library-crud.md +111 -0
- package/skills/weaver-e10-jinchengda/references/contract-clause-recommender.md +0 -15
- package/skills/weaver-e10-jinchengda/references/contract-clause-reference-save.md +0 -13
- package/skills/weaver-e10-jinchengda/references/contract-credit-page.md +50 -0
- package/skills/weaver-e10-jinchengda/references/contract-disabled-capabilities.md +4 -2
- package/skills/weaver-e10-jinchengda/references/contract-doc-compare.md +74 -0
- package/skills/weaver-e10-jinchengda/references/contract-flow-launch.md +84 -0
- package/skills/weaver-e10-jinchengda/references/contract-performance-query.md +29 -0
- package/skills/weaver-e10-jinchengda/references/contract-quote-to-contract.md +28 -0
- package/skills/weaver-e10-jinchengda/references/contract-request-status.md +2 -21
- package/skills/weaver-e10-jinchengda/references/contract-request-write.md +0 -24
- package/skills/weaver-e10-jinchengda/references/contract-signing-subjects.md +0 -15
- package/skills/weaver-e10-jinchengda/references/contract-subject-create.md +0 -17
- package/skills/weaver-e10-jinchengda/references/contract-template-recommend.md +70 -0
- package/skills/weaver-e10-jinchengda/references/contract-template-selector.md +0 -15
- package/skills/weaver-e10-jinchengda/references/contract-workflow-discovery.md +0 -15
- package/skills/weaver-e10-jinchengda/references/source-manifest.json +1168 -152
- package/skills/weaver-e10-meeting/SKILL.md +493 -17
- package/skills/weaver-e10-meeting/references/meeting-change.md +4 -4
- package/skills/weaver-e10-meeting/references/meeting-create.md +6 -6
- package/skills/weaver-e10-meeting/references/meeting-eb.md +503 -27
- package/skills/weaver-e10-meeting/references/meeting-invitation.md +113 -0
- package/skills/weaver-e10-meeting/references/meeting-lifecycle.md +6 -6
- package/skills/weaver-e10-meeting/references/meeting-minute-file.md +425 -0
- package/skills/weaver-e10-meeting/references/meeting-queries.md +4 -4
- package/skills/weaver-e10-meeting/references/meeting-receipts-signs.md +15 -15
- package/skills/weaver-e10-meeting/references/meeting-verification.md +19 -11
- package/skills/weaver-e10-meeting.zip +0 -0
- package/skills/weaver-e10-workflow/SKILL.md +23 -1
- package/skills/weaver-e10-workflow/references/todo-smart-convert.md +282 -0
- package/skills/weaver-e10-workflow/scripts/todo-summary.cjs +695 -0
- package/skills/weaver-e10-yepiaotong/SKILL.md +15 -11
- package/skills/weaver-e10-yepiaotong/references/invoice-enterprise-list.md +1 -1
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing-examples.md +10 -7
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing-form-fill-rules.md +41 -14
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing-workflow.md +54 -26
- package/skills/weaver-e10-yepiaotong/references/invoice-personal-list.md +6 -5
- package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +14 -11
- package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +97 -56
- package/skills/weaver-e10-yepiaotong/references/reim-examples.md +84 -60
- package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +142 -105
- package/skills/weaver-e10-yepiaotong/references/reim-matching-rules.md +53 -194
- package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +7 -7
- package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +164 -72
- package/skills/weaver-e10-yepiaotong/references/source-manifest.json +8 -2
- package/templates/meeting/invitation.docx +0 -0
|
@@ -0,0 +1,2482 @@
|
|
|
1
|
+
import { createRequire as __esbuildCreateRequire } from 'node:module';
|
|
2
|
+
const require = __esbuildCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
E10ApiError,
|
|
5
|
+
createE10RequestRuntime,
|
|
6
|
+
requireE10Session
|
|
7
|
+
} from "./chunk-H3WDBYJW.js";
|
|
8
|
+
import {
|
|
9
|
+
E10_SESSION_EXPIRED_MESSAGE,
|
|
10
|
+
getActiveProfile
|
|
11
|
+
} from "./chunk-324YPTC2.js";
|
|
12
|
+
import {
|
|
13
|
+
CliError,
|
|
14
|
+
isCliError,
|
|
15
|
+
toErrorEnvelope
|
|
16
|
+
} from "./chunk-LUSPKZKY.js";
|
|
17
|
+
import "./chunk-BUSC6UAE.js";
|
|
18
|
+
|
|
19
|
+
// src/shortcuts/okr/index.ts
|
|
20
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
21
|
+
|
|
22
|
+
// src/shortcuts/okr/continuation.ts
|
|
23
|
+
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
24
|
+
import { existsSync } from "node:fs";
|
|
25
|
+
import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
26
|
+
import { homedir } from "node:os";
|
|
27
|
+
import { resolve } from "node:path";
|
|
28
|
+
|
|
29
|
+
// src/shortcuts/okr/errors.ts
|
|
30
|
+
var OkrCliError = class extends CliError {
|
|
31
|
+
type;
|
|
32
|
+
subtype;
|
|
33
|
+
code;
|
|
34
|
+
retryable;
|
|
35
|
+
stage;
|
|
36
|
+
details;
|
|
37
|
+
partialData;
|
|
38
|
+
constructor(type, subtype, message, options = {}) {
|
|
39
|
+
super(message, options.exitCode ?? 5 /* InternalError */);
|
|
40
|
+
this.name = "OkrCliError";
|
|
41
|
+
this.type = type;
|
|
42
|
+
this.subtype = subtype;
|
|
43
|
+
this.code = options.code;
|
|
44
|
+
this.retryable = options.retryable ?? false;
|
|
45
|
+
this.stage = options.stage;
|
|
46
|
+
this.details = options.details;
|
|
47
|
+
this.partialData = options.partialData;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
function okrValidationError(subtype, message, details) {
|
|
51
|
+
return new OkrCliError("validation", subtype, message, {
|
|
52
|
+
details,
|
|
53
|
+
exitCode: 2 /* UsageError */
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function okrAuthError(subtype, message, details) {
|
|
57
|
+
return new OkrCliError("authentication", subtype, message, {
|
|
58
|
+
details,
|
|
59
|
+
exitCode: 3 /* AuthError */
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function okrNetworkError(subtype, message, options = {}) {
|
|
63
|
+
return new OkrCliError("network", subtype, message, {
|
|
64
|
+
...options,
|
|
65
|
+
retryable: options.retryable ?? true,
|
|
66
|
+
exitCode: 4 /* NetworkError */
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function okrApiError(subtype, message, details) {
|
|
70
|
+
return new OkrCliError("api", subtype, message, {
|
|
71
|
+
details,
|
|
72
|
+
exitCode: 1 /* GeneralError */
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function okrConfirmationError(action, details) {
|
|
76
|
+
return new OkrCliError("confirmation", "required", "\u8BE5\u64CD\u4F5C\u9700\u8981\u660E\u786E\u786E\u8BA4", {
|
|
77
|
+
details: { action, ...details },
|
|
78
|
+
exitCode: 10 /* ConfirmationRequired */
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function okrUnsupportedError(subtype, message, details) {
|
|
82
|
+
return new OkrCliError("policy", subtype, message, {
|
|
83
|
+
details,
|
|
84
|
+
exitCode: 6 /* PolicyError */
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function okrPartialError(message, partialData, details) {
|
|
88
|
+
return new OkrCliError("partial", "write_uncertain", message, {
|
|
89
|
+
details,
|
|
90
|
+
partialData,
|
|
91
|
+
exitCode: 11 /* Partial */
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function isOkrErrorType(error, type) {
|
|
95
|
+
return Boolean(error && typeof error === "object" && error.type === type);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/shortcuts/okr/continuation.ts
|
|
99
|
+
function okrStateRoot(ctx) {
|
|
100
|
+
const configured = ctx?.config?.path();
|
|
101
|
+
if (configured) return resolve(configured, "..");
|
|
102
|
+
return process.env.WEAVER_WORK_CLI_HOME || process.env.WORK_CLI_HOME || resolve(homedir(), ".weaver-work-cli");
|
|
103
|
+
}
|
|
104
|
+
async function loadKey(ctx) {
|
|
105
|
+
const keysDir = resolve(okrStateRoot(ctx), "keys");
|
|
106
|
+
const filename = resolve(keysDir, "okr-continuation.key");
|
|
107
|
+
await mkdir(keysDir, { recursive: true, mode: 448 });
|
|
108
|
+
if (existsSync(filename)) return readFile(filename);
|
|
109
|
+
const key = randomBytes(32);
|
|
110
|
+
try {
|
|
111
|
+
await writeFile(filename, key, { flag: "wx", mode: 384 });
|
|
112
|
+
if (process.platform !== "win32") await chmod(filename, 384).catch(() => void 0);
|
|
113
|
+
return key;
|
|
114
|
+
} catch {
|
|
115
|
+
return readFile(filename);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function encode(value) {
|
|
119
|
+
return Buffer.from(JSON.stringify(value)).toString("base64url");
|
|
120
|
+
}
|
|
121
|
+
function signature(payload, key) {
|
|
122
|
+
return createHmac("sha256", key).update(payload).digest("base64url");
|
|
123
|
+
}
|
|
124
|
+
function createOkrContinuationSigner(ctx) {
|
|
125
|
+
return {
|
|
126
|
+
async issue(payload, ttlMs = 10 * 6e4) {
|
|
127
|
+
const issuedAt = Date.now();
|
|
128
|
+
const body = encode({ ...payload, issuedAt, expiresAt: issuedAt + ttlMs });
|
|
129
|
+
const sig = signature(body, await loadKey(ctx));
|
|
130
|
+
return `${body}.${sig}`;
|
|
131
|
+
},
|
|
132
|
+
async verify(token, expectedOperation) {
|
|
133
|
+
if (typeof token !== "string" || !token.includes(".")) {
|
|
134
|
+
throw okrValidationError("continuation_invalid", "continuation \u65E0\u6548");
|
|
135
|
+
}
|
|
136
|
+
const [body, provided] = token.split(".");
|
|
137
|
+
const expected = signature(body, await loadKey(ctx));
|
|
138
|
+
const valid = provided.length === expected.length && timingSafeEqual(Buffer.from(provided), Buffer.from(expected));
|
|
139
|
+
if (!valid) throw okrValidationError("continuation_invalid", "continuation \u7B7E\u540D\u6821\u9A8C\u5931\u8D25");
|
|
140
|
+
let value;
|
|
141
|
+
try {
|
|
142
|
+
value = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
|
|
143
|
+
} catch {
|
|
144
|
+
throw okrValidationError("continuation_invalid", "continuation \u5185\u5BB9\u65E0\u6CD5\u89E3\u6790");
|
|
145
|
+
}
|
|
146
|
+
if (value.operation !== expectedOperation) {
|
|
147
|
+
throw okrValidationError("continuation_mismatch", "continuation \u4E0D\u5C5E\u4E8E\u5F53\u524D\u64CD\u4F5C");
|
|
148
|
+
}
|
|
149
|
+
if (!Number.isSafeInteger(value.expiresAt) || value.expiresAt < Date.now()) {
|
|
150
|
+
throw okrValidationError("continuation_expired", "continuation \u5DF2\u8FC7\u671F");
|
|
151
|
+
}
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/shortcuts/okr/host.ts
|
|
158
|
+
import { createHash } from "node:crypto";
|
|
159
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
160
|
+
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
161
|
+
import { resolve as resolve2 } from "node:path";
|
|
162
|
+
function inferProfile(ctx) {
|
|
163
|
+
const options = ctx.getGlobalOptions();
|
|
164
|
+
return options.profile || getActiveProfile();
|
|
165
|
+
}
|
|
166
|
+
function cacheFilename(root, key) {
|
|
167
|
+
const digest = createHash("sha256").update(key).digest("hex").slice(0, 40);
|
|
168
|
+
return resolve2(root, "cache", "okr", `${digest}.json`);
|
|
169
|
+
}
|
|
170
|
+
async function readCacheFile(root, key) {
|
|
171
|
+
const file = cacheFilename(root, key);
|
|
172
|
+
if (!existsSync2(file)) return void 0;
|
|
173
|
+
try {
|
|
174
|
+
const parsed = JSON.parse(await readFile2(file, "utf8"));
|
|
175
|
+
if (parsed.key !== key) return void 0;
|
|
176
|
+
if (typeof parsed.expiresAt === "number" && parsed.expiresAt < Date.now()) return void 0;
|
|
177
|
+
return parsed.value;
|
|
178
|
+
} catch {
|
|
179
|
+
return void 0;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function writeCacheFile(root, key, value, ttlMs) {
|
|
183
|
+
const file = cacheFilename(root, key);
|
|
184
|
+
await mkdir2(resolve2(file, ".."), { recursive: true });
|
|
185
|
+
const payload = {
|
|
186
|
+
key,
|
|
187
|
+
value,
|
|
188
|
+
expiresAt: ttlMs === void 0 ? null : Date.now() + ttlMs,
|
|
189
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
190
|
+
};
|
|
191
|
+
await writeFile2(file, `${JSON.stringify(payload)}
|
|
192
|
+
`, "utf8");
|
|
193
|
+
}
|
|
194
|
+
function businessMessage(value) {
|
|
195
|
+
if (!value || typeof value !== "object") return "\u6CDB\u5FAE\u63A5\u53E3\u8FD4\u56DE\u4E1A\u52A1\u5931\u8D25";
|
|
196
|
+
const candidates = [
|
|
197
|
+
value.msg,
|
|
198
|
+
value.message,
|
|
199
|
+
value.resultMsg,
|
|
200
|
+
value.datajson?.message,
|
|
201
|
+
value.datajson?.msg
|
|
202
|
+
];
|
|
203
|
+
for (const item of candidates) {
|
|
204
|
+
if (typeof item === "string" && item.trim()) return item;
|
|
205
|
+
}
|
|
206
|
+
return "\u6CDB\u5FAE\u63A5\u53E3\u8FD4\u56DE\u4E1A\u52A1\u5931\u8D25";
|
|
207
|
+
}
|
|
208
|
+
function isDatajsonSuccess(value) {
|
|
209
|
+
const status = value?.datajson?.status;
|
|
210
|
+
return status === true || status === "true";
|
|
211
|
+
}
|
|
212
|
+
function isFlagSuccess(value) {
|
|
213
|
+
const status = value?.status;
|
|
214
|
+
return status === "1" || status === 1 || status === true;
|
|
215
|
+
}
|
|
216
|
+
function assertPath(requestPath) {
|
|
217
|
+
if (typeof requestPath !== "string" || !requestPath.startsWith("/") || requestPath.startsWith("//")) {
|
|
218
|
+
throw okrValidationError("path_invalid", "\u8BF7\u6C42\u8DEF\u5F84\u5FC5\u987B\u662F\u76F8\u5BF9\u7EDD\u5BF9\u8DEF\u5F84");
|
|
219
|
+
}
|
|
220
|
+
if (/^https?:/i.test(requestPath) || /[\r\n]/.test(requestPath) || requestPath.includes("/../")) {
|
|
221
|
+
throw okrValidationError("path_invalid", "\u8BF7\u6C42\u8DEF\u5F84\u4E0D\u5141\u8BB8\u8DE8\u57DF\u6216\u8DEF\u5F84\u9003\u9038");
|
|
222
|
+
}
|
|
223
|
+
if (!requestPath.startsWith("/api/")) {
|
|
224
|
+
throw okrValidationError("path_not_allowed", "OKR \u76EE\u6807\u6A21\u5757\u53EA\u80FD\u8C03\u7528 /api/ \u8DEF\u5F84");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function omitEmptyQueryValues(query) {
|
|
228
|
+
if (!query) return void 0;
|
|
229
|
+
return Object.fromEntries(
|
|
230
|
+
Object.entries(query).filter(([, value]) => value !== "" && value !== void 0 && value !== null)
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
function mapRuntimeNetworkError(error) {
|
|
234
|
+
if (error instanceof E10ApiError && error.type === "network") {
|
|
235
|
+
throw okrNetworkError(error.subtype, error.message, {
|
|
236
|
+
retryable: error.retryable,
|
|
237
|
+
details: error.details
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
throw error;
|
|
241
|
+
}
|
|
242
|
+
function createOkrHost(ctx, dependencies = {}) {
|
|
243
|
+
let e10Session = null;
|
|
244
|
+
let sessionContext = null;
|
|
245
|
+
const requireSession = dependencies.requireSession || requireE10Session;
|
|
246
|
+
const cacheRoot = okrStateRoot(ctx);
|
|
247
|
+
async function ensureSession() {
|
|
248
|
+
if (!e10Session) {
|
|
249
|
+
e10Session = await requireSession(ctx);
|
|
250
|
+
sessionContext = {
|
|
251
|
+
baseUrl: e10Session.getBaseUrl(),
|
|
252
|
+
profile: inferProfile(ctx),
|
|
253
|
+
userId: e10Session.userId,
|
|
254
|
+
tenantKey: e10Session.tenantKey,
|
|
255
|
+
eteamsId: e10Session.eteamsId
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
return e10Session;
|
|
259
|
+
}
|
|
260
|
+
async function getSession() {
|
|
261
|
+
await ensureSession();
|
|
262
|
+
return sessionContext;
|
|
263
|
+
}
|
|
264
|
+
async function runtime() {
|
|
265
|
+
return createE10RequestRuntime(ctx, await ensureSession(), {
|
|
266
|
+
interceptors: dependencies.interceptors,
|
|
267
|
+
fetch: dependencies.fetch
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
async function request(request2) {
|
|
271
|
+
const { method, path, query, body, operation, timeoutMs = 3e4 } = request2;
|
|
272
|
+
assertPath(path);
|
|
273
|
+
let response;
|
|
274
|
+
try {
|
|
275
|
+
response = await (await runtime()).requestJson({
|
|
276
|
+
module: "okr",
|
|
277
|
+
operation,
|
|
278
|
+
method: (method || "POST").toUpperCase(),
|
|
279
|
+
path,
|
|
280
|
+
query: omitEmptyQueryValues(query),
|
|
281
|
+
body,
|
|
282
|
+
headers: { "X-Requested-With": "XMLHttpRequest" },
|
|
283
|
+
timeoutMs,
|
|
284
|
+
bigIntStrings: true
|
|
285
|
+
});
|
|
286
|
+
} catch (error) {
|
|
287
|
+
mapRuntimeNetworkError(error);
|
|
288
|
+
}
|
|
289
|
+
if (response.status === 401 || response.status === 302) {
|
|
290
|
+
throw okrAuthError(
|
|
291
|
+
"session_expired",
|
|
292
|
+
E10_SESSION_EXPIRED_MESSAGE,
|
|
293
|
+
{ httpStatus: response.status }
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
if (response.parseError) {
|
|
297
|
+
throw okrNetworkError("protocol", `\u63A5\u53E3\u8FD4\u56DE\u4E0D\u662F\u5408\u6CD5 JSON\uFF08HTTP ${response.status}\uFF09`, { retryable: false });
|
|
298
|
+
}
|
|
299
|
+
if (response.status === 404) {
|
|
300
|
+
throw new OkrCliError(
|
|
301
|
+
"api",
|
|
302
|
+
"endpoint_not_found",
|
|
303
|
+
`\u63A5\u53E3\u8FD4\u56DE 404\uFF0C\u5F53\u524D\u73AF\u5883\u53EF\u80FD\u672A\u5B89\u88C5\u300COKR \u76EE\u6807\u300D\u76F8\u5173\u5E94\u7528\u6216\u672A\u90E8\u7F72\u8BE5\u63A5\u53E3\uFF08${path}\uFF09`,
|
|
304
|
+
{ code: response.status, details: { path }, exitCode: 1 }
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
if (response.status < 200 || response.status >= 300) {
|
|
308
|
+
throw new OkrCliError("api", "http_error", `\u6CDB\u5FAE\u63A5\u53E3 HTTP ${response.status}`, {
|
|
309
|
+
code: response.status,
|
|
310
|
+
details: { status: response.status, message: businessMessage(response.value) },
|
|
311
|
+
exitCode: 1
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
return response.value;
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
request,
|
|
318
|
+
getSession,
|
|
319
|
+
getCache: (key) => readCacheFile(cacheRoot, key),
|
|
320
|
+
setCache: (key, value, ttlMs) => writeCacheFile(cacheRoot, key, value, ttlMs)
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// src/shortcuts/okr/operations/shared.ts
|
|
325
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
326
|
+
|
|
327
|
+
// src/shortcuts/okr/operations/types.ts
|
|
328
|
+
function okrSuccess(action, data, meta) {
|
|
329
|
+
const payload = { ok: true, action, data };
|
|
330
|
+
if (meta && Object.keys(meta).length > 0) payload.meta = meta;
|
|
331
|
+
return payload;
|
|
332
|
+
}
|
|
333
|
+
function schemaOf(properties, options = {}) {
|
|
334
|
+
return {
|
|
335
|
+
type: "object",
|
|
336
|
+
additionalProperties: false,
|
|
337
|
+
properties,
|
|
338
|
+
...options.required?.length ? { required: options.required } : {},
|
|
339
|
+
...options.oneOf?.length ? { oneOf: options.oneOf } : {},
|
|
340
|
+
...options.anyOf?.length ? { anyOf: options.anyOf } : {},
|
|
341
|
+
...options.description ? { description: options.description } : {}
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
var SCHEMA_ID = {
|
|
345
|
+
oneOf: [{ type: "integer" }, { type: "string", pattern: "^\\d+$" }]
|
|
346
|
+
};
|
|
347
|
+
var SCHEMA_PERSON_ID = { type: "string", minLength: 1, pattern: "^\\d+$" };
|
|
348
|
+
var SCHEMA_ID_LIST_TEXT = { type: "string", pattern: "^\\d+(,\\d+)*$" };
|
|
349
|
+
var SCHEMA_DATE = { type: "string", pattern: "^\\d{4}-\\d{2}-\\d{2}$" };
|
|
350
|
+
var PERIOD_TYPE_VALUES = ["1", "2", "3", "4"];
|
|
351
|
+
var SCHEMA_PERIOD_TYPE = { type: "string", enum: [...PERIOD_TYPE_VALUES] };
|
|
352
|
+
var QUARTER_VALUES = ["1", "2", "3", "4"];
|
|
353
|
+
var SCHEMA_QUARTER = { type: "string", enum: [...QUARTER_VALUES] };
|
|
354
|
+
var SCOPE_VALUES = ["1", "2"];
|
|
355
|
+
var SCHEMA_SCOPE = { type: "string", enum: [...SCOPE_VALUES] };
|
|
356
|
+
var PERIOD_TYPE_LABELS = {
|
|
357
|
+
"1": "\u5E74\u5EA6",
|
|
358
|
+
"2": "\u5B63\u5EA6",
|
|
359
|
+
"3": "\u6708\u5EA6",
|
|
360
|
+
"4": "\u81EA\u5B9A\u4E49"
|
|
361
|
+
};
|
|
362
|
+
var STANDARD_STATUS_LABELS = {
|
|
363
|
+
"0": "\u8349\u7A3F",
|
|
364
|
+
"1": "\u8FDB\u884C\u4E2D",
|
|
365
|
+
"2": "\u5DF2\u5B8C\u6210",
|
|
366
|
+
"3": "\u5DF2\u64A4\u9500",
|
|
367
|
+
"4": "\u76EE\u6807\u5236\u5B9A\u5F85\u5BA1\u6279",
|
|
368
|
+
"5": "\u76EE\u6807\u66F4\u65B0\u5F85\u5BA1\u6279",
|
|
369
|
+
"6": "\u76EE\u6807\u5B8C\u6210\u5F85\u5BA1\u6279"
|
|
370
|
+
};
|
|
371
|
+
var EB_M_STATUS_LABELS = {
|
|
372
|
+
"1": "\u8FDB\u884C\u4E2D",
|
|
373
|
+
"2": "\u5DF2\u5B8C\u6210",
|
|
374
|
+
"3": "\u5DF2\u64A4\u9500",
|
|
375
|
+
"4": "\u5BA1\u6279\u4E2D",
|
|
376
|
+
"5": "\u672A\u5F00\u59CB"
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
// src/shortcuts/okr/operations/shared.ts
|
|
380
|
+
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
381
|
+
var FORBIDDEN_INPUT_KEYS = /* @__PURE__ */ new Set([
|
|
382
|
+
"authorization",
|
|
383
|
+
"cookie",
|
|
384
|
+
"eteamsid",
|
|
385
|
+
"access_token",
|
|
386
|
+
"app_key",
|
|
387
|
+
"app_secret",
|
|
388
|
+
"token",
|
|
389
|
+
"user_agent"
|
|
390
|
+
]);
|
|
391
|
+
function asObject(value) {
|
|
392
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
393
|
+
throw okrValidationError("input_not_object", "\u8F93\u5165\u5FC5\u987B\u662F JSON \u5BF9\u8C61");
|
|
394
|
+
}
|
|
395
|
+
return value;
|
|
396
|
+
}
|
|
397
|
+
function assertNoForbiddenKeys(input) {
|
|
398
|
+
for (const key of Object.keys(input)) {
|
|
399
|
+
if (FORBIDDEN_KEYS.has(key)) {
|
|
400
|
+
throw okrValidationError("forbidden_key", `\u8F93\u5165\u5305\u542B\u975E\u6CD5\u5B57\u6BB5\uFF1A${key}`);
|
|
401
|
+
}
|
|
402
|
+
if (FORBIDDEN_INPUT_KEYS.has(key.toLowerCase())) {
|
|
403
|
+
throw okrValidationError("field_forbidden", `\u7981\u6B62\u4E1A\u52A1\u8F93\u5165\u5B57\u6BB5\uFF1A${key}\uFF08\u8BA4\u8BC1\u7531 CLI \u6258\u7BA1\uFF09`);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function toIdString(value, field) {
|
|
408
|
+
if (value === void 0 || value === null || value === "") {
|
|
409
|
+
throw okrValidationError("id_invalid", `${field} \u5FC5\u987B\u662F\u6570\u5B57 ID\uFF08\u96EA\u82B1 ID \u8BF7\u7528\u5B57\u7B26\u4E32\u4F20\u9012\uFF09`);
|
|
410
|
+
}
|
|
411
|
+
const text = String(value);
|
|
412
|
+
if (!/^\d+$/.test(text)) {
|
|
413
|
+
throw okrValidationError("id_invalid", `${field} \u5FC5\u987B\u662F\u6570\u5B57 ID`);
|
|
414
|
+
}
|
|
415
|
+
return text;
|
|
416
|
+
}
|
|
417
|
+
function toPersonIdString(value, field) {
|
|
418
|
+
if (value === void 0 || value === null || value === "") {
|
|
419
|
+
throw okrValidationError("person_id_required", `${field} \u5FC5\u586B`);
|
|
420
|
+
}
|
|
421
|
+
const text = String(value);
|
|
422
|
+
if (!/^\d+$/.test(text)) {
|
|
423
|
+
throw okrValidationError(
|
|
424
|
+
"person_id_invalid",
|
|
425
|
+
`${field} \u5FC5\u987B\u662F\u4EBA\u5458 ID\uFF08\u6570\u5B57\u5B57\u7B26\u4E32\uFF09\uFF0C\u4E0D\u80FD\u76F4\u63A5\u4F20\u4EBA\u5458\u540D\u79F0\uFF1B\u8BF7\u5148\u901A\u8FC7 weaver-e10-hrm skill \u7528\u59D3\u540D\u89E3\u6790\u51FA id \u6216 employeeId\uFF08\u7981\u6B62\u53D6 userId \u5B57\u6BB5\uFF09`,
|
|
426
|
+
{ field, value: text }
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
return text;
|
|
430
|
+
}
|
|
431
|
+
function toPersonIdListText(value, field) {
|
|
432
|
+
const list = [];
|
|
433
|
+
if (Array.isArray(value)) {
|
|
434
|
+
for (const item of value) {
|
|
435
|
+
if (item === void 0 || item === null || item === "") continue;
|
|
436
|
+
list.push(String(item));
|
|
437
|
+
}
|
|
438
|
+
} else if (typeof value === "string" || typeof value === "number") {
|
|
439
|
+
for (const part of String(value).split(",")) {
|
|
440
|
+
const trimmed = part.trim();
|
|
441
|
+
if (trimmed) list.push(trimmed);
|
|
442
|
+
}
|
|
443
|
+
} else {
|
|
444
|
+
throw okrValidationError("person_id_invalid", `${field} \u5FC5\u987B\u662F\u4EBA\u5458 ID \u6216\u4EBA\u5458 ID \u6570\u7EC4`);
|
|
445
|
+
}
|
|
446
|
+
if (list.length === 0) {
|
|
447
|
+
throw okrValidationError("person_id_required", `${field} \u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u4EBA\u5458 ID`);
|
|
448
|
+
}
|
|
449
|
+
for (const id of list) {
|
|
450
|
+
if (!/^\d+$/.test(id)) {
|
|
451
|
+
throw okrValidationError(
|
|
452
|
+
"person_id_invalid",
|
|
453
|
+
`${field} \u5FC5\u987B\u662F\u4EBA\u5458 ID\uFF08\u6570\u5B57\u5B57\u7B26\u4E32\uFF09\uFF0C\u4E0D\u80FD\u76F4\u63A5\u4F20\u4EBA\u5458\u540D\u79F0\uFF1B\u8BF7\u5148\u901A\u8FC7 weaver-e10-hrm skill \u89E3\u6790`,
|
|
454
|
+
{ field, value: id }
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return list.join(",");
|
|
459
|
+
}
|
|
460
|
+
function compact(value) {
|
|
461
|
+
for (const key of Object.keys(value)) {
|
|
462
|
+
const item = value[key];
|
|
463
|
+
if (item === void 0 || item === null || item === "") delete value[key];
|
|
464
|
+
}
|
|
465
|
+
return value;
|
|
466
|
+
}
|
|
467
|
+
function optionValue(value) {
|
|
468
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
469
|
+
if (Array.isArray(value)) {
|
|
470
|
+
const first = value[0];
|
|
471
|
+
if (first === void 0 || first === null) return void 0;
|
|
472
|
+
if (typeof first === "string" || typeof first === "number") return String(first);
|
|
473
|
+
if (typeof first === "object") {
|
|
474
|
+
const record = first;
|
|
475
|
+
const candidate = record.id ?? record.value ?? record.name;
|
|
476
|
+
if (candidate === void 0 || candidate === null || candidate === "") return void 0;
|
|
477
|
+
return String(candidate);
|
|
478
|
+
}
|
|
479
|
+
return void 0;
|
|
480
|
+
}
|
|
481
|
+
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
482
|
+
return void 0;
|
|
483
|
+
}
|
|
484
|
+
function ebMainTables(value) {
|
|
485
|
+
const datas = value?.datajson?.datas;
|
|
486
|
+
if (!Array.isArray(datas)) return [];
|
|
487
|
+
const list = [];
|
|
488
|
+
for (const item of datas) {
|
|
489
|
+
if (item && typeof item === "object" && item.mainTable && typeof item.mainTable === "object") {
|
|
490
|
+
list.push(item.mainTable);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return list;
|
|
494
|
+
}
|
|
495
|
+
function fingerprint(value) {
|
|
496
|
+
return createHash2("sha256").update(JSON.stringify(value ?? null)).digest("hex").slice(0, 32);
|
|
497
|
+
}
|
|
498
|
+
function requireConfirm(args, action) {
|
|
499
|
+
if (args.confirm !== true) {
|
|
500
|
+
throw okrConfirmationError(action, {
|
|
501
|
+
hint: "\u91CD\u65B0\u8C03\u7528\u65F6\u4F20\u5165 confirm=true \u4E0E prepare \u8FD4\u56DE\u7684 continuation"
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
async function ensureConfirmLease(args, action, env) {
|
|
506
|
+
requireConfirm(args, action);
|
|
507
|
+
const lease = await env.continuation.verify(args.continuation, action);
|
|
508
|
+
const session = await env.host.getSession();
|
|
509
|
+
if (lease.baseUrl !== session.baseUrl || lease.profile !== session.profile || lease.userId !== session.userId) {
|
|
510
|
+
throw okrValidationError("context_mismatch", "\u786E\u8BA4\u4E0A\u4E0B\u6587\u5DF2\u53D8\u5316\uFF08\u79DF\u6237\u6216\u767B\u5F55\u8D26\u53F7\u4E0D\u540C\uFF09\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C prepare");
|
|
511
|
+
}
|
|
512
|
+
return lease;
|
|
513
|
+
}
|
|
514
|
+
function assertLinkSupported(link, supported, capability, message, details) {
|
|
515
|
+
if (link !== supported) {
|
|
516
|
+
throw okrUnsupportedError("link_unsupported", message, {
|
|
517
|
+
capability,
|
|
518
|
+
link,
|
|
519
|
+
expectedLink: supported,
|
|
520
|
+
...details || {}
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
function pad(value) {
|
|
525
|
+
return String(value).padStart(2, "0");
|
|
526
|
+
}
|
|
527
|
+
function lastDayOfMonth(year, month) {
|
|
528
|
+
return new Date(Date.UTC(year, month, 0)).getUTCDate();
|
|
529
|
+
}
|
|
530
|
+
function assertPeriodType(value) {
|
|
531
|
+
const text = value === void 0 || value === null ? "" : String(value);
|
|
532
|
+
if (!["1", "2", "3", "4"].includes(text)) {
|
|
533
|
+
throw okrValidationError("period_type_invalid", "period_type \u53D6\u503C\u5FC5\u987B\u662F 1\uFF08\u5E74\u5EA6\uFF09/ 2\uFF08\u5B63\u5EA6\uFF09/ 3\uFF08\u6708\u5EA6\uFF09/ 4\uFF08\u81EA\u5B9A\u4E49\uFF09");
|
|
534
|
+
}
|
|
535
|
+
return text;
|
|
536
|
+
}
|
|
537
|
+
function resolvePeriod(args) {
|
|
538
|
+
const periodType = assertPeriodType(args.period_type);
|
|
539
|
+
const periodRange = args.period_range;
|
|
540
|
+
if (typeof periodRange !== "string" || !periodRange.trim()) {
|
|
541
|
+
throw okrValidationError("period_range_required", "period_range\uFF08\u5468\u671F\u8303\u56F4\uFF09\u5FC5\u586B\uFF0C\u683C\u5F0F\u968F period_type \u53D8\u5316");
|
|
542
|
+
}
|
|
543
|
+
const range = periodRange.trim();
|
|
544
|
+
const spec = { periodType, periodRange: range };
|
|
545
|
+
if (periodType === "1") {
|
|
546
|
+
if (!/^\d{4}$/.test(range)) {
|
|
547
|
+
throw okrValidationError("period_range_invalid", '\u5E74\u5EA6\u76EE\u6807\u7684 period_range \u5FC5\u987B\u662F\u5E74\u4EFD\u5B57\u7B26\u4E32\uFF0C\u793A\u4F8B "2026"');
|
|
548
|
+
}
|
|
549
|
+
return spec;
|
|
550
|
+
}
|
|
551
|
+
if (periodType === "2") {
|
|
552
|
+
if (!/^\d{4}$/.test(range)) {
|
|
553
|
+
throw okrValidationError("period_range_invalid", '\u5B63\u5EA6\u76EE\u6807\u7684 period_range \u5FC5\u987B\u662F\u5E74\u4EFD\u5B57\u7B26\u4E32\uFF0C\u793A\u4F8B "2026"');
|
|
554
|
+
}
|
|
555
|
+
const quarter = args.period_quarter === void 0 || args.period_quarter === null || args.period_quarter === "" ? "" : String(args.period_quarter);
|
|
556
|
+
if (!["1", "2", "3", "4"].includes(quarter)) {
|
|
557
|
+
throw okrValidationError("period_quarter_invalid", "\u5B63\u5EA6\u76EE\u6807\u7684 period_quarter \u5FC5\u586B\uFF0C\u53D6\u503C 1/2/3/4");
|
|
558
|
+
}
|
|
559
|
+
spec.periodQuarter = quarter;
|
|
560
|
+
return spec;
|
|
561
|
+
}
|
|
562
|
+
if (periodType === "3") {
|
|
563
|
+
if (!/^\d{4}-\d{2}$/.test(range)) {
|
|
564
|
+
throw okrValidationError("period_range_invalid", '\u6708\u5EA6\u76EE\u6807\u7684 period_range \u5FC5\u987B\u662F yyyy-MM \u683C\u5F0F\uFF0C\u793A\u4F8B "2026-04"');
|
|
565
|
+
}
|
|
566
|
+
return spec;
|
|
567
|
+
}
|
|
568
|
+
if (!/^\d{4}-\d{2}-\d{2},\d{4}-\d{2}-\d{2}$/.test(range)) {
|
|
569
|
+
throw okrValidationError(
|
|
570
|
+
"period_range_invalid",
|
|
571
|
+
'\u81EA\u5B9A\u4E49\u5468\u671F\u76EE\u6807\u7684 period_range \u5FC5\u987B\u662F\u300C\u5F00\u59CB\u65E5\u671F,\u7ED3\u675F\u65E5\u671F\u300D\u683C\u5F0F\uFF0C\u793A\u4F8B "2026-01-01,2026-12-31"'
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
const [start, end] = range.split(",");
|
|
575
|
+
if (start > end) {
|
|
576
|
+
throw okrValidationError("period_range_invalid", "\u81EA\u5B9A\u4E49\u5468\u671F\u7684\u5F00\u59CB\u65E5\u671F\u4E0D\u80FD\u665A\u4E8E\u7ED3\u675F\u65E5\u671F");
|
|
577
|
+
}
|
|
578
|
+
return spec;
|
|
579
|
+
}
|
|
580
|
+
function ebPeriodFields(spec) {
|
|
581
|
+
const fields = { period_type: spec.periodType };
|
|
582
|
+
if (spec.periodType === "1") {
|
|
583
|
+
const year = Number(spec.periodRange);
|
|
584
|
+
fields.period_year = spec.periodRange;
|
|
585
|
+
fields.period_range_0 = `${year}-01-01`;
|
|
586
|
+
fields.period_range_1 = `${year}-12-31`;
|
|
587
|
+
return fields;
|
|
588
|
+
}
|
|
589
|
+
if (spec.periodType === "2") {
|
|
590
|
+
const year = Number(spec.periodRange);
|
|
591
|
+
const quarter = Number(spec.periodQuarter);
|
|
592
|
+
const startMonth = (quarter - 1) * 3 + 1;
|
|
593
|
+
const endMonth = startMonth + 2;
|
|
594
|
+
fields.period_year = spec.periodRange;
|
|
595
|
+
fields.period_quarter = String(quarter);
|
|
596
|
+
fields.period_range_0 = `${year}-${pad(startMonth)}-01`;
|
|
597
|
+
fields.period_range_1 = `${year}-${pad(endMonth)}-${pad(lastDayOfMonth(year, endMonth))}`;
|
|
598
|
+
return fields;
|
|
599
|
+
}
|
|
600
|
+
if (spec.periodType === "3") {
|
|
601
|
+
const [yearText, monthText] = spec.periodRange.split("-");
|
|
602
|
+
const year = Number(yearText);
|
|
603
|
+
const month = Number(monthText);
|
|
604
|
+
fields.period_year = yearText;
|
|
605
|
+
fields.period_month = spec.periodRange;
|
|
606
|
+
fields.period_range_0 = `${yearText}-${monthText}-01`;
|
|
607
|
+
fields.period_range_1 = `${yearText}-${monthText}-${pad(lastDayOfMonth(year, month))}`;
|
|
608
|
+
return fields;
|
|
609
|
+
}
|
|
610
|
+
const [start, end] = spec.periodRange.split(",");
|
|
611
|
+
fields.period_range_0 = start;
|
|
612
|
+
fields.period_range_1 = end;
|
|
613
|
+
return fields;
|
|
614
|
+
}
|
|
615
|
+
function ebPeriodFilters(spec) {
|
|
616
|
+
const fields = ebPeriodFields(spec);
|
|
617
|
+
const filters = {
|
|
618
|
+
period_type: spec.periodType,
|
|
619
|
+
period_range_0: fields.period_range_0,
|
|
620
|
+
period_range_1: fields.period_range_1
|
|
621
|
+
};
|
|
622
|
+
if (fields.period_year) filters.period_year = fields.period_year;
|
|
623
|
+
if (spec.periodType === "2") filters.period_quarter = String(spec.periodQuarter);
|
|
624
|
+
else if (fields.period_month) filters.period_month = fields.period_month;
|
|
625
|
+
return filters;
|
|
626
|
+
}
|
|
627
|
+
function asText(value) {
|
|
628
|
+
if (value === void 0 || value === null) return null;
|
|
629
|
+
const text = String(value);
|
|
630
|
+
return text === "" ? null : text;
|
|
631
|
+
}
|
|
632
|
+
function asNumber(value) {
|
|
633
|
+
if (value === void 0 || value === null || value === "") return null;
|
|
634
|
+
const numeric = Number(value);
|
|
635
|
+
return Number.isFinite(numeric) ? numeric : null;
|
|
636
|
+
}
|
|
637
|
+
function periodTypeLabelOf(periodType) {
|
|
638
|
+
return periodType ? PERIOD_TYPE_LABELS[periodType] ?? null : null;
|
|
639
|
+
}
|
|
640
|
+
function normalizeStandardGoal(item, detailUrl, keyresultList) {
|
|
641
|
+
const periodType = asText(item?.periodType);
|
|
642
|
+
const status = asText(item?.status);
|
|
643
|
+
return {
|
|
644
|
+
goalId: asText(item?.id),
|
|
645
|
+
name: asText(item?.name),
|
|
646
|
+
principalid: asText(item?.principalid),
|
|
647
|
+
principalName: asText(item?.principalName),
|
|
648
|
+
periodType,
|
|
649
|
+
periodTypeLabel: periodTypeLabelOf(periodType),
|
|
650
|
+
periodRange: asText(item?.periodRange),
|
|
651
|
+
periodStart: asText(item?.periodStart),
|
|
652
|
+
periodEnd: asText(item?.periodEnd),
|
|
653
|
+
status,
|
|
654
|
+
statusLabel: status ? STANDARD_STATUS_LABELS[status] ?? null : null,
|
|
655
|
+
progress: asNumber(item?.progress),
|
|
656
|
+
score: asNumber(item?.score),
|
|
657
|
+
parentId: asText(item?.parentId),
|
|
658
|
+
creator: asText(item?.creator),
|
|
659
|
+
createTime: asText(item?.createTime),
|
|
660
|
+
remark: asText(item?.remark),
|
|
661
|
+
detailUrl,
|
|
662
|
+
...keyresultList === void 0 ? {} : { keyresultList }
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
function normalizeEbGoal(mainTable, detailUrl) {
|
|
666
|
+
const periodType = optionValue(mainTable?.period_type) ?? null;
|
|
667
|
+
const mStatus = optionValue(mainTable?.m_status) ?? null;
|
|
668
|
+
const start = asText(optionValue(mainTable?.period_range_0));
|
|
669
|
+
const end = asText(optionValue(mainTable?.period_range_1));
|
|
670
|
+
const principal = mainTable?.principalid;
|
|
671
|
+
const principalName = Array.isArray(principal) ? asText(principal[0]?.name ?? principal[0]?.value) : asText(principal?.name);
|
|
672
|
+
return {
|
|
673
|
+
goalId: asText(mainTable?.id),
|
|
674
|
+
name: asText(mainTable?.obj_name),
|
|
675
|
+
principalid: Array.isArray(principal) ? asText(principal[0]?.id ?? principal[0]) : asText(typeof principal === "object" && principal ? principal.id : principal),
|
|
676
|
+
principalName,
|
|
677
|
+
periodType,
|
|
678
|
+
periodTypeLabel: periodTypeLabelOf(periodType),
|
|
679
|
+
periodRange: start && end ? `${start} ~ ${end}` : start ?? end,
|
|
680
|
+
periodStart: start,
|
|
681
|
+
periodEnd: end,
|
|
682
|
+
status: mStatus,
|
|
683
|
+
statusLabel: mStatus ? EB_M_STATUS_LABELS[mStatus] ?? null : null,
|
|
684
|
+
progress: asNumber(optionValue(mainTable?.progress)),
|
|
685
|
+
score: asNumber(optionValue(mainTable?.score)),
|
|
686
|
+
parentId: asText(optionValue(mainTable?.parent_id)),
|
|
687
|
+
creator: asText(optionValue(mainTable?.creator)),
|
|
688
|
+
createTime: asText(mainTable?.create_time),
|
|
689
|
+
remark: asText(mainTable?.remark),
|
|
690
|
+
detailUrl
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
function buildGoalTable(goals) {
|
|
694
|
+
const columns = ["\u76EE\u6807\u540D\u79F0", "\u76EE\u6807\u8D23\u4EFB\u4EBA\u540D\u79F0", "\u76EE\u6807\u5468\u671F\u7C7B\u578B", "\u76EE\u6807\u5468\u671F\u8303\u56F4"];
|
|
695
|
+
const rows = goals.map((goal) => ({
|
|
696
|
+
name: goal.name ?? "",
|
|
697
|
+
principalName: goal.principalName ?? "",
|
|
698
|
+
periodType: goal.periodTypeLabel ?? "",
|
|
699
|
+
periodRange: goal.periodRange ?? "",
|
|
700
|
+
view_link: goal.detailUrl,
|
|
701
|
+
anchor: goal.name ?? ""
|
|
702
|
+
}));
|
|
703
|
+
const header = `| ${columns.join(" | ")} |`;
|
|
704
|
+
const divider = `| ${columns.map(() => "---").join(" | ")} |`;
|
|
705
|
+
const body = rows.map((row) => {
|
|
706
|
+
const nameCell = row.view_link ? `[${row.anchor}](${row.view_link})` : row.anchor;
|
|
707
|
+
return `| ${nameCell} | ${row.principalName} | ${row.periodType} | ${row.periodRange} |`;
|
|
708
|
+
});
|
|
709
|
+
return {
|
|
710
|
+
columns,
|
|
711
|
+
rows,
|
|
712
|
+
markdown: [header, divider, ...body].join("\n")
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// src/shortcuts/okr/operations/link.ts
|
|
717
|
+
var OKR_APP_TAG = "weaver-wr-goal-eb";
|
|
718
|
+
var OKR_EB_FORM_TAG = "uf_wrgm_baseinfo";
|
|
719
|
+
var VERSION_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
720
|
+
var EB_FORM_ID_FIXED = {
|
|
721
|
+
tqasclatif: "1027322801024458753"
|
|
722
|
+
};
|
|
723
|
+
function okrVersionCacheKey(tenantKey) {
|
|
724
|
+
return `okr:version:${tenantKey}`;
|
|
725
|
+
}
|
|
726
|
+
function okrEbFormCacheKey(tenantKey) {
|
|
727
|
+
return `okr:ebform:${tenantKey}`;
|
|
728
|
+
}
|
|
729
|
+
function isEbVersion(verName) {
|
|
730
|
+
if (typeof verName !== "string") return false;
|
|
731
|
+
const match = /^[vV]?(\d+)/.exec(verName.trim());
|
|
732
|
+
if (!match) return false;
|
|
733
|
+
return Number(match[1]) >= 2;
|
|
734
|
+
}
|
|
735
|
+
async function resolveLink(host, options = {}) {
|
|
736
|
+
const session = await host.getSession();
|
|
737
|
+
const key = okrVersionCacheKey(session.tenantKey);
|
|
738
|
+
if (!options.refresh) {
|
|
739
|
+
const cached = await host.getCache(key);
|
|
740
|
+
const value = cached && typeof cached === "object" ? cached : null;
|
|
741
|
+
if (value && (value.link === "standard" || value.link === "eb")) {
|
|
742
|
+
return {
|
|
743
|
+
link: value.link,
|
|
744
|
+
verName: value.verName ?? null,
|
|
745
|
+
tenantKey: session.tenantKey,
|
|
746
|
+
cached: true,
|
|
747
|
+
degraded: false,
|
|
748
|
+
reason: null,
|
|
749
|
+
checkedAt: typeof value.checkedAt === "string" ? value.checkedAt : (/* @__PURE__ */ new Date()).toISOString()
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
let verName = null;
|
|
754
|
+
let degraded = false;
|
|
755
|
+
let reason = null;
|
|
756
|
+
try {
|
|
757
|
+
const response = await host.request({
|
|
758
|
+
method: "POST",
|
|
759
|
+
path: "/api/ebuilder/form/formdata/v2/getFormDataList/okr_searchAppver",
|
|
760
|
+
operation: "okr.version.check",
|
|
761
|
+
body: {
|
|
762
|
+
datajson: {
|
|
763
|
+
mainTable: {},
|
|
764
|
+
pageInfo: { pageNo: "1", pageSize: "10" },
|
|
765
|
+
header: { operator: session.userId }
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
});
|
|
769
|
+
const mainTable = ebMainTables(response)[0];
|
|
770
|
+
verName = optionValue(mainTable?.ver_name) ?? null;
|
|
771
|
+
} catch (error) {
|
|
772
|
+
if (isOkrErrorType(error, "api") || isOkrErrorType(error, "network")) {
|
|
773
|
+
degraded = true;
|
|
774
|
+
reason = error.message;
|
|
775
|
+
} else {
|
|
776
|
+
throw error;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
const link = isEbVersion(verName) ? "eb" : "standard";
|
|
780
|
+
const info = {
|
|
781
|
+
link,
|
|
782
|
+
verName,
|
|
783
|
+
tenantKey: session.tenantKey,
|
|
784
|
+
cached: false,
|
|
785
|
+
degraded,
|
|
786
|
+
reason,
|
|
787
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
788
|
+
};
|
|
789
|
+
if (!degraded) await host.setCache(key, info, VERSION_CACHE_TTL_MS);
|
|
790
|
+
return info;
|
|
791
|
+
}
|
|
792
|
+
function firstId(value) {
|
|
793
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
794
|
+
const first = value[0];
|
|
795
|
+
if (typeof first === "string" || typeof first === "number") return String(first);
|
|
796
|
+
if (first && typeof first === "object") {
|
|
797
|
+
const record = first;
|
|
798
|
+
const candidate = record.id ?? record.objId ?? record.idobjId ?? record.value;
|
|
799
|
+
if (candidate !== void 0 && candidate !== null && candidate !== "") return String(candidate);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
803
|
+
return void 0;
|
|
804
|
+
}
|
|
805
|
+
function pickObjIdByTag(value, formTag) {
|
|
806
|
+
const root = value && typeof value === "object" && "datajson" in value ? value.datajson : value;
|
|
807
|
+
const data = root?.data;
|
|
808
|
+
if (!Array.isArray(data)) return firstId(root);
|
|
809
|
+
const objects = data.filter((item) => item && typeof item === "object");
|
|
810
|
+
if (objects.length > 0) {
|
|
811
|
+
const tagged = objects.filter((item) => item.tag !== void 0 && item.tag !== null);
|
|
812
|
+
const matched = tagged.find((item) => String(item.tag) === formTag);
|
|
813
|
+
if (matched) return firstId([matched]);
|
|
814
|
+
if (tagged.length > 0) return void 0;
|
|
815
|
+
return firstId(objects);
|
|
816
|
+
}
|
|
817
|
+
return firstId(data);
|
|
818
|
+
}
|
|
819
|
+
async function resolveEbFormId(host) {
|
|
820
|
+
const session = await host.getSession();
|
|
821
|
+
const templateOf = (formId2) => `/sp/ebdfpage/card/0/${formId2}/{goalId}`;
|
|
822
|
+
const fixed = EB_FORM_ID_FIXED[session.tenantKey];
|
|
823
|
+
if (fixed) {
|
|
824
|
+
return {
|
|
825
|
+
appTag: OKR_APP_TAG,
|
|
826
|
+
appId: null,
|
|
827
|
+
formTag: OKR_EB_FORM_TAG,
|
|
828
|
+
formId: fixed,
|
|
829
|
+
source: "fixed",
|
|
830
|
+
detailUrlTemplate: templateOf(fixed)
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
const key = okrEbFormCacheKey(session.tenantKey);
|
|
834
|
+
const cached = await host.getCache(key);
|
|
835
|
+
const cachedValue = cached && typeof cached === "object" ? cached : null;
|
|
836
|
+
if (cachedValue && typeof cachedValue.formId === "string" && cachedValue.formId) {
|
|
837
|
+
return {
|
|
838
|
+
appTag: OKR_APP_TAG,
|
|
839
|
+
appId: typeof cachedValue.appId === "string" ? cachedValue.appId : null,
|
|
840
|
+
formTag: OKR_EB_FORM_TAG,
|
|
841
|
+
formId: cachedValue.formId,
|
|
842
|
+
source: "cache",
|
|
843
|
+
detailUrlTemplate: templateOf(cachedValue.formId)
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
const appIdsResponse = await host.request({
|
|
847
|
+
method: "GET",
|
|
848
|
+
path: "/api/bs/ebuilder/app/tags/getAppIds",
|
|
849
|
+
query: { tag: OKR_APP_TAG },
|
|
850
|
+
operation: "okr.eb.form.resolve"
|
|
851
|
+
}).catch(() => void 0);
|
|
852
|
+
const appId = firstId(appIdsResponse?.data);
|
|
853
|
+
if (!appId) {
|
|
854
|
+
throw okrApiError(
|
|
855
|
+
"eb_app_not_found",
|
|
856
|
+
`\u672A\u68C0\u6D4B\u5230\u300COKR \u76EE\u6807\u300Debuilder \u5E94\u7528\uFF08appTag: ${OKR_APP_TAG}\uFF09\uFF0C\u65E0\u6CD5\u751F\u6210\u76EE\u6807\u8BE6\u60C5\u9875\u94FE\u63A5`
|
|
857
|
+
);
|
|
858
|
+
}
|
|
859
|
+
const formResponse = await host.request({
|
|
860
|
+
method: "GET",
|
|
861
|
+
path: "/api/ebuilder/form/obj/getObjsByTag",
|
|
862
|
+
query: { tag: OKR_EB_FORM_TAG, appId },
|
|
863
|
+
operation: "okr.eb.form.resolve"
|
|
864
|
+
}).catch(() => void 0);
|
|
865
|
+
const formId = pickObjIdByTag(formResponse, OKR_EB_FORM_TAG);
|
|
866
|
+
if (!formId) {
|
|
867
|
+
throw okrApiError(
|
|
868
|
+
"eb_form_not_found",
|
|
869
|
+
`\u672A\u627E\u5230\u76EE\u6807\u8BE6\u60C5 ebuilder \u8868\u5355\uFF08tag: ${OKR_EB_FORM_TAG}\uFF09\uFF0C\u65E0\u6CD5\u751F\u6210\u76EE\u6807\u8BE6\u60C5\u9875\u94FE\u63A5`
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
const info = {
|
|
873
|
+
appTag: OKR_APP_TAG,
|
|
874
|
+
appId,
|
|
875
|
+
formTag: OKR_EB_FORM_TAG,
|
|
876
|
+
formId,
|
|
877
|
+
source: "dynamic",
|
|
878
|
+
detailUrlTemplate: templateOf(formId)
|
|
879
|
+
};
|
|
880
|
+
await host.setCache(key, { appId, formId });
|
|
881
|
+
return info;
|
|
882
|
+
}
|
|
883
|
+
function buildStandardDetailPath(goalId) {
|
|
884
|
+
return `/sp/goal/openDetail?id=${goalId}`;
|
|
885
|
+
}
|
|
886
|
+
function okrAbsoluteUrl(baseUrl, path) {
|
|
887
|
+
if (!path) return null;
|
|
888
|
+
if (/^https?:\/\//iu.test(path)) return path;
|
|
889
|
+
const origin = String(baseUrl ?? "").replace(/\/+$/u, "");
|
|
890
|
+
const suffix = path.startsWith("/") ? path : `/${path}`;
|
|
891
|
+
return `${origin}${suffix}`;
|
|
892
|
+
}
|
|
893
|
+
async function createDetailUrlResolver(host, link) {
|
|
894
|
+
const warnings = [];
|
|
895
|
+
if (link === "standard") {
|
|
896
|
+
return {
|
|
897
|
+
warnings,
|
|
898
|
+
async resolve(goalId) {
|
|
899
|
+
return goalId ? buildStandardDetailPath(goalId) : null;
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
let formId = null;
|
|
904
|
+
let resolved = false;
|
|
905
|
+
return {
|
|
906
|
+
warnings,
|
|
907
|
+
async resolve(goalId) {
|
|
908
|
+
if (!goalId) return null;
|
|
909
|
+
if (!resolved) {
|
|
910
|
+
resolved = true;
|
|
911
|
+
try {
|
|
912
|
+
formId = (await resolveEbFormId(host)).formId;
|
|
913
|
+
} catch (error) {
|
|
914
|
+
warnings.push(`\u76EE\u6807\u8BE6\u60C5\u9875\u94FE\u63A5\u6682\u4E0D\u53EF\u7528\uFF1A${error.message}`);
|
|
915
|
+
formId = null;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
return formId ? `/sp/ebdfpage/card/0/${formId}/${goalId}` : null;
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
async function fetchGoalRaw(host, link, goalId) {
|
|
923
|
+
const session = await host.getSession();
|
|
924
|
+
if (link === "standard") {
|
|
925
|
+
const response2 = await host.request({
|
|
926
|
+
method: "GET",
|
|
927
|
+
path: `/api/workrelate/goal/getObjectDetail/${goalId}`,
|
|
928
|
+
operation: "okr.get"
|
|
929
|
+
});
|
|
930
|
+
return response2?.data?.obj ?? null;
|
|
931
|
+
}
|
|
932
|
+
const response = await host.request({
|
|
933
|
+
method: "POST",
|
|
934
|
+
path: "/api/ebuilder/form/formdata/v2/getFormDataByPk/okr_queryGoal",
|
|
935
|
+
operation: "okr.get",
|
|
936
|
+
body: {
|
|
937
|
+
datajson: {
|
|
938
|
+
mainTable: { id: goalId },
|
|
939
|
+
header: { operator: session.userId }
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
});
|
|
943
|
+
if (!isDatajsonSuccess(response)) {
|
|
944
|
+
throw okrApiError("business_error", businessMessage(response), { response: businessMessage(response) });
|
|
945
|
+
}
|
|
946
|
+
return ebMainTables(response)[0] ?? null;
|
|
947
|
+
}
|
|
948
|
+
function goalPrincipalId(raw, link) {
|
|
949
|
+
if (!raw || typeof raw !== "object") return null;
|
|
950
|
+
if (link === "standard") {
|
|
951
|
+
const value = raw.principalid;
|
|
952
|
+
return value === void 0 || value === null || value === "" ? null : String(value);
|
|
953
|
+
}
|
|
954
|
+
return optionValue(raw.principalid) ?? null;
|
|
955
|
+
}
|
|
956
|
+
function buildStandardSaveBody(input) {
|
|
957
|
+
return compact({
|
|
958
|
+
...input.goalId ? { id: input.goalId } : {},
|
|
959
|
+
name: input.name,
|
|
960
|
+
scopeId: input.scopeId,
|
|
961
|
+
...input.scopeId === "2" && input.scopeDataId ? { scopeDataId: input.scopeDataId } : {},
|
|
962
|
+
periodType: input.periodType,
|
|
963
|
+
periodRange: input.periodRange,
|
|
964
|
+
...input.periodType === "2" && input.periodQuarter ? { periodQuarter: input.periodQuarter } : {},
|
|
965
|
+
principalid: input.principalid,
|
|
966
|
+
...input.partners ? { partners: input.partners } : {},
|
|
967
|
+
...input.remark === void 0 ? {} : { remark: input.remark },
|
|
968
|
+
...input.keyresultList ? { keyresultList: input.keyresultList } : {},
|
|
969
|
+
status: input.status,
|
|
970
|
+
parentId: input.parentId ?? "0"
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// src/shortcuts/okr/operations/read.ts
|
|
975
|
+
var okrVersionCheck = {
|
|
976
|
+
name: "okr.version.check",
|
|
977
|
+
resource: "okr",
|
|
978
|
+
method: "version.check",
|
|
979
|
+
action: "okr.version.check",
|
|
980
|
+
summary: "\u5224\u5B9A\u5F53\u524D\u79DF\u6237\u7684 OKR \u76EE\u6807\u63A5\u53E3\u94FE\u8DEF\uFF08standard / eb\uFF09\uFF1A\u5148\u8BFB 1 \u5929\u79DF\u6237\u7F13\u5B58\uFF0C\u672A\u547D\u4E2D\u624D\u8C03\u7528 okr_searchAppver \u8BFB\u53D6 ver_name",
|
|
981
|
+
capability: "okr",
|
|
982
|
+
risk: "read",
|
|
983
|
+
inputSchema: schemaOf({
|
|
984
|
+
refresh: { type: "boolean", default: false, description: "true \u65F6\u5FFD\u7565\u7F13\u5B58\u91CD\u65B0\u8C03\u7528\u7248\u672C\u63A5\u53E3" }
|
|
985
|
+
}),
|
|
986
|
+
handler: async (args, { host }) => {
|
|
987
|
+
const info = await resolveLink(host, { refresh: args.refresh === true });
|
|
988
|
+
return okrSuccess("okr.version.check", {
|
|
989
|
+
...info,
|
|
990
|
+
versionInterface: "okr_searchAppver"
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
};
|
|
994
|
+
var okrEbFormResolve = {
|
|
995
|
+
name: "okr.eb.form.resolve",
|
|
996
|
+
resource: "okr",
|
|
997
|
+
method: "eb.form.resolve",
|
|
998
|
+
action: "okr.eb.form.resolve",
|
|
999
|
+
summary: "\u89E3\u6790 ebuilder \u76EE\u6807\u8BE6\u60C5\u8868\u5355 id\uFF08appTag weaver-wr-goal-eb + formTag uf_wrgm_baseinfo\uFF09\uFF0C\u7528\u4E8E\u751F\u6210\u76EE\u6807\u8BE6\u60C5\u9875\u94FE\u63A5\uFF1B\u7ED3\u679C\u6309\u79DF\u6237\u957F\u671F\u7F13\u5B58",
|
|
1000
|
+
capability: "okr",
|
|
1001
|
+
risk: "read",
|
|
1002
|
+
inputSchema: schemaOf({}),
|
|
1003
|
+
handler: async (_args, { host }) => {
|
|
1004
|
+
const { link } = await resolveLink(host);
|
|
1005
|
+
assertLinkSupported(
|
|
1006
|
+
link,
|
|
1007
|
+
"eb",
|
|
1008
|
+
"okr.eb.form.resolve",
|
|
1009
|
+
"\u5F53\u524D\u79DF\u6237\u8D70 e10 \u6807\u51C6\u7248\u94FE\u8DEF\uFF0C\u76EE\u6807\u8BE6\u60C5\u9875\u5730\u5740\u4E3A /sp/goal/openDetail?id=\u76EE\u6807id\uFF0C\u65E0\u9700 ebuilder \u8868\u5355 id"
|
|
1010
|
+
);
|
|
1011
|
+
const info = await resolveEbFormId(host);
|
|
1012
|
+
return okrSuccess("okr.eb.form.resolve", { ...info, appTag: info.appTag, formTag: OKR_EB_FORM_TAG });
|
|
1013
|
+
}
|
|
1014
|
+
};
|
|
1015
|
+
function toIdList(value) {
|
|
1016
|
+
if (Array.isArray(value)) return value.map((item) => toIdString(item, "ids"));
|
|
1017
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
1018
|
+
return String(value).split(",").map((part) => part.trim()).filter((part) => part !== "").map((part) => toIdString(part, "ids"));
|
|
1019
|
+
}
|
|
1020
|
+
throw okrValidationError("ids_required", "ids \u5FC5\u586B\uFF0C\u4F20\u76EE\u6807 ID \u6570\u7EC4\u6216\u82F1\u6587\u9017\u53F7\u62FC\u63A5\u7684\u76EE\u6807 ID \u5B57\u7B26\u4E32");
|
|
1021
|
+
}
|
|
1022
|
+
var okrViewlink = {
|
|
1023
|
+
name: "okr.viewlink",
|
|
1024
|
+
resource: "okr",
|
|
1025
|
+
method: "viewlink",
|
|
1026
|
+
action: "okr.viewlink",
|
|
1027
|
+
summary: "\u4E3A\u5DF2\u6709\u76EE\u6807 ID \u751F\u6210\u53EF\u70B9\u51FB\u7684\u76EE\u6807\u8BE6\u60C5\u9875\u94FE\u63A5\uFF08\u6807\u51C6\u7248 /sp/goal/openDetail?id=\uFF0Ceb \u7248 /sp/ebdfpage/card/0/\u8868\u5355id/\u76EE\u6807id\uFF09",
|
|
1028
|
+
capability: "okr",
|
|
1029
|
+
risk: "read",
|
|
1030
|
+
inputSchema: schemaOf(
|
|
1031
|
+
{
|
|
1032
|
+
ids: {
|
|
1033
|
+
oneOf: [
|
|
1034
|
+
{ type: "array", items: SCHEMA_ID, minItems: 1 },
|
|
1035
|
+
{ type: "string", pattern: "^\\d+(,\\d+)*$" }
|
|
1036
|
+
],
|
|
1037
|
+
description: "\u76EE\u6807 ID \u6570\u7EC4\uFF0C\u6216\u82F1\u6587\u9017\u53F7\u62FC\u63A5\u7684\u76EE\u6807 ID \u5B57\u7B26\u4E32"
|
|
1038
|
+
},
|
|
1039
|
+
anchor: { type: "string", minLength: 1, description: "\u94FE\u63A5\u5C55\u793A\u6587\u6848\uFF0C\u9ED8\u8BA4\u7528\u76EE\u6807\u540D\u79F0\uFF1B\u672A\u67E5\u8BE6\u60C5\u65F6\u9ED8\u8BA4\u300C\u67E5\u770B\u8BE6\u60C5\u300D" }
|
|
1040
|
+
},
|
|
1041
|
+
{ required: ["ids"] }
|
|
1042
|
+
),
|
|
1043
|
+
handler: async (args, { host }) => {
|
|
1044
|
+
const ids = toIdList(args.ids);
|
|
1045
|
+
const { link } = await resolveLink(host);
|
|
1046
|
+
const resolver = await createDetailUrlResolver(host, link);
|
|
1047
|
+
const links = [];
|
|
1048
|
+
const session = await host.getSession();
|
|
1049
|
+
for (const id of ids) {
|
|
1050
|
+
const path = await resolver.resolve(id);
|
|
1051
|
+
links.push({
|
|
1052
|
+
goalId: id,
|
|
1053
|
+
path,
|
|
1054
|
+
url: okrAbsoluteUrl(session.baseUrl, path),
|
|
1055
|
+
anchor: typeof args.anchor === "string" && args.anchor ? args.anchor : "\u67E5\u770B\u8BE6\u60C5"
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
const available = links.every((item) => Boolean(item.path));
|
|
1059
|
+
if (!available) {
|
|
1060
|
+
return okrSuccess("okr.viewlink", {
|
|
1061
|
+
status: "VIEWLINK_UNAVAILABLE",
|
|
1062
|
+
link,
|
|
1063
|
+
available: false,
|
|
1064
|
+
links,
|
|
1065
|
+
warnings: resolver.warnings.length > 0 ? resolver.warnings : ["\u76EE\u6807\u8BE6\u60C5\u9875\u94FE\u63A5\u6682\u4E0D\u53EF\u7528"]
|
|
1066
|
+
});
|
|
1067
|
+
}
|
|
1068
|
+
return okrSuccess("okr.viewlink", { status: "COMPLETE", link, available: true, links });
|
|
1069
|
+
}
|
|
1070
|
+
};
|
|
1071
|
+
function pageOf(args) {
|
|
1072
|
+
const pageNo = args.page_no === void 0 ? 1 : Number(args.page_no);
|
|
1073
|
+
const pageSize = args.page_size === void 0 ? 10 : Number(args.page_size);
|
|
1074
|
+
if (!Number.isInteger(pageNo) || pageNo < 1) {
|
|
1075
|
+
throw okrValidationError("page_invalid", "page_no \u5FC5\u987B\u662F\u5927\u4E8E 0 \u7684\u6574\u6570");
|
|
1076
|
+
}
|
|
1077
|
+
if (!Number.isInteger(pageSize) || pageSize < 1 || pageSize > 100) {
|
|
1078
|
+
throw okrValidationError("page_invalid", "page_size \u5FC5\u987B\u662F 1 \u5230 100 \u4E4B\u95F4\u7684\u6574\u6570");
|
|
1079
|
+
}
|
|
1080
|
+
return { pageNo, pageSize };
|
|
1081
|
+
}
|
|
1082
|
+
function resolveQueryScope(args) {
|
|
1083
|
+
const scope = args.query_scope === void 0 ? "self" : String(args.query_scope);
|
|
1084
|
+
if (scope !== "self" && scope !== "all") {
|
|
1085
|
+
throw okrValidationError("query_scope_invalid", "query_scope \u53D6\u503C\u5FC5\u987B\u662F self\uFF08\u672C\u4EBA\u5BF9\u5E94\u5468\u671F\uFF09\u6216 all\uFF08\u8DE8\u4EBA\u68C0\u7D22\uFF09");
|
|
1086
|
+
}
|
|
1087
|
+
return scope;
|
|
1088
|
+
}
|
|
1089
|
+
var okrList = {
|
|
1090
|
+
name: "okr.list",
|
|
1091
|
+
resource: "okr",
|
|
1092
|
+
method: "list",
|
|
1093
|
+
action: "okr.list",
|
|
1094
|
+
summary: "\u5206\u9875\u67E5\u8BE2 OKR \u76EE\u6807\uFF0C\u8FD4\u56DE\u56FA\u5B9A\u56DB\u5217\uFF08\u76EE\u6807\u540D\u79F0\u3001\u76EE\u6807\u8D23\u4EFB\u4EBA\u540D\u79F0\u3001\u76EE\u6807\u5468\u671F\u7C7B\u578B\u3001\u76EE\u6807\u5468\u671F\u8303\u56F4\uFF09\u7684\u8868\u683C\uFF0C\u76EE\u6807\u540D\u79F0\u53EF\u70B9\u51FB\u8DF3\u8F6C\u8BE6\u60C5",
|
|
1095
|
+
capability: "okr",
|
|
1096
|
+
risk: "read",
|
|
1097
|
+
inputSchema: schemaOf(
|
|
1098
|
+
{
|
|
1099
|
+
query_scope: {
|
|
1100
|
+
type: "string",
|
|
1101
|
+
enum: ["self", "all"],
|
|
1102
|
+
default: "self",
|
|
1103
|
+
description: "self=\u67E5\u8BE2\u672C\u4EBA\u5BF9\u5E94\u5468\u671F\u76EE\u6807\uFF1Ball=\u6309\u6761\u4EF6\u8DE8\u4EBA\u68C0\u7D22"
|
|
1104
|
+
},
|
|
1105
|
+
period_type: { type: "string", enum: ["1", "2", "3", "4"], description: "\u5468\u671F\u7C7B\u578B\uFF1A1-\u5E74\u5EA6 2-\u5B63\u5EA6 3-\u6708\u5EA6 4-\u81EA\u5B9A\u4E49\uFF08self \u5FC5\u586B\uFF09" },
|
|
1106
|
+
period_range: { type: "string", description: "\u5468\u671F\u8303\u56F4\uFF1A\u5E74\u5EA6/\u5B63\u5EA6\u4E3A yyyy\uFF0C\u6708\u5EA6\u4E3A yyyy-MM\uFF0C\u81EA\u5B9A\u4E49\u4E3A\u300C\u5F00\u59CB\u65E5\u671F,\u7ED3\u675F\u65E5\u671F\u300D" },
|
|
1107
|
+
period_quarter: { type: "string", enum: ["1", "2", "3", "4"], description: "\u5B63\u5EA6\u503C\uFF08period_type=2 \u65F6\u5FC5\u586B\uFF09" },
|
|
1108
|
+
name: { type: "string", minLength: 1, description: "\u76EE\u6807\u540D\u79F0\u5173\u952E\u5B57\uFF08\u4EC5\u6807\u51C6\u7248\u94FE\u8DEF\uFF0C\u6A21\u7CCA\u5339\u914D\uFF09" },
|
|
1109
|
+
principalid: SCHEMA_PERSON_ID,
|
|
1110
|
+
status: { type: "string", pattern: "^\\d+(,\\d+)*$", description: "\u76EE\u6807\u72B6\u6001\u7801\uFF0C\u82F1\u6587\u9017\u53F7\u62FC\u63A5\uFF08\u4EC5\u6807\u51C6\u7248\u94FE\u8DEF\uFF09" },
|
|
1111
|
+
match: { type: "string", enum: ["and", "or"], default: "and", description: "\u591A\u6761\u4EF6\u5173\u7CFB\uFF08\u4EC5\u6807\u51C6\u7248\u94FE\u8DEF\uFF09" },
|
|
1112
|
+
page_no: { type: "integer", minimum: 1, default: 1 },
|
|
1113
|
+
page_size: { type: "integer", minimum: 1, maximum: 100, default: 10 }
|
|
1114
|
+
},
|
|
1115
|
+
{ description: "self \u6A21\u5F0F\u5FC5\u586B period_type + period_range\uFF1Ball \u6A21\u5F0F\u6309\u9700\u4F20 name / principalid / status" }
|
|
1116
|
+
),
|
|
1117
|
+
handler: async (args, { host }) => {
|
|
1118
|
+
const { pageNo, pageSize } = pageOf(args);
|
|
1119
|
+
const queryScope = resolveQueryScope(args);
|
|
1120
|
+
const { link } = await resolveLink(host);
|
|
1121
|
+
const session = await host.getSession();
|
|
1122
|
+
const resolver = await createDetailUrlResolver(host, link);
|
|
1123
|
+
const warnings = [];
|
|
1124
|
+
const notes = [];
|
|
1125
|
+
const hasPeriod = args.period_type !== void 0 || args.period_range !== void 0;
|
|
1126
|
+
if (queryScope === "self" && !hasPeriod) {
|
|
1127
|
+
throw okrValidationError("period_required", "query_scope=self \u65F6\u5FC5\u987B\u4F20 period_type \u4E0E period_range");
|
|
1128
|
+
}
|
|
1129
|
+
const period = hasPeriod ? resolvePeriod(args) : null;
|
|
1130
|
+
let goals = [];
|
|
1131
|
+
let raw;
|
|
1132
|
+
let paging = {};
|
|
1133
|
+
if (link === "standard") {
|
|
1134
|
+
const body = compact({
|
|
1135
|
+
page: pageNo,
|
|
1136
|
+
pageSize,
|
|
1137
|
+
viewType: "list",
|
|
1138
|
+
...queryScope === "self" ? {
|
|
1139
|
+
condtype: "1",
|
|
1140
|
+
subcondtype: "1",
|
|
1141
|
+
status: 1,
|
|
1142
|
+
statusList: [{ content: "0,1,4,5,6" }]
|
|
1143
|
+
} : {
|
|
1144
|
+
condtype: "4",
|
|
1145
|
+
subcondtype: "6",
|
|
1146
|
+
isMore: 0,
|
|
1147
|
+
scopeId: "0",
|
|
1148
|
+
hideSubDep: 0,
|
|
1149
|
+
hideSub: 1,
|
|
1150
|
+
statusList: [{ content: args.status === void 0 ? "1,2,4,5,6,7" : String(args.status) }],
|
|
1151
|
+
type: args.match === void 0 ? "and" : String(args.match),
|
|
1152
|
+
...args.name === void 0 ? {} : { nameList: [{ mode: "contain", content: String(args.name) }] },
|
|
1153
|
+
...args.principalid === void 0 ? {} : { principalidList: [{ mode: "eq", content: toPersonIdString(args.principalid, "principalid") }] }
|
|
1154
|
+
}
|
|
1155
|
+
});
|
|
1156
|
+
if (period) {
|
|
1157
|
+
body.periodType = period.periodType;
|
|
1158
|
+
body.periodRange = period.periodRange;
|
|
1159
|
+
if (period.periodQuarter) body.periodQuarter = Number(period.periodQuarter);
|
|
1160
|
+
}
|
|
1161
|
+
raw = await host.request({
|
|
1162
|
+
method: "POST",
|
|
1163
|
+
path: "/api/workrelate/goal/getSearchList",
|
|
1164
|
+
operation: "okr.list",
|
|
1165
|
+
body
|
|
1166
|
+
});
|
|
1167
|
+
const list = Array.isArray(raw?.data?.list) ? raw.data.list : [];
|
|
1168
|
+
goals = [];
|
|
1169
|
+
for (const item of list) {
|
|
1170
|
+
const goalId = item?.id === void 0 || item?.id === null ? null : String(item.id);
|
|
1171
|
+
const detailUrl = okrAbsoluteUrl(session.baseUrl, await resolver.resolve(goalId));
|
|
1172
|
+
goals.push(normalizeStandardGoal(item, detailUrl, item?.keyresultList));
|
|
1173
|
+
}
|
|
1174
|
+
const total = raw?.data?.total ?? raw?.data?.count;
|
|
1175
|
+
if (total !== void 0 && total !== null) paging.total = Number(total);
|
|
1176
|
+
paging.hasNext = list.length === pageSize;
|
|
1177
|
+
} else {
|
|
1178
|
+
if (args.name !== void 0 || args.status !== void 0) {
|
|
1179
|
+
throw okrValidationError(
|
|
1180
|
+
"link_filter_unsupported",
|
|
1181
|
+
"ebuilder \u94FE\u8DEF\u7684\u5206\u9875\u67E5\u8BE2\u63A5\u53E3\u4E0D\u652F\u6301\u6309\u76EE\u6807\u540D\u79F0\u5173\u952E\u5B57\u6216\u76EE\u6807\u72B6\u6001\u7B5B\u9009\uFF1B\u8BF7\u6539\u7528 query_scope=self \u6216 principalid + \u5468\u671F\u6761\u4EF6",
|
|
1182
|
+
{ link, unsupportedFilters: ["name", "status"] }
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1185
|
+
const mainTable = compact({
|
|
1186
|
+
...queryScope === "self" ? { creator: session.userId } : {},
|
|
1187
|
+
...args.principalid === void 0 ? {} : { principalid: toPersonIdString(args.principalid, "principalid") },
|
|
1188
|
+
...period ? ebPeriodFilters(period) : {}
|
|
1189
|
+
});
|
|
1190
|
+
raw = await host.request({
|
|
1191
|
+
method: "POST",
|
|
1192
|
+
path: "/api/ebuilder/form/formdata/v2/getFormDataList/okr_pageQueryGoal",
|
|
1193
|
+
operation: "okr.list",
|
|
1194
|
+
body: {
|
|
1195
|
+
datajson: {
|
|
1196
|
+
mainTable,
|
|
1197
|
+
pageInfo: { pageNo: String(pageNo), pageSize: String(pageSize) },
|
|
1198
|
+
header: { operator: session.userId }
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
});
|
|
1202
|
+
if (!isDatajsonSuccess(raw)) {
|
|
1203
|
+
throw okrApiError("business_error", businessMessage(raw), { response: businessMessage(raw) });
|
|
1204
|
+
}
|
|
1205
|
+
const tables = ebMainTables(raw);
|
|
1206
|
+
goals = [];
|
|
1207
|
+
for (const mainTable2 of tables) {
|
|
1208
|
+
const goalId = mainTable2?.id === void 0 || mainTable2?.id === null ? null : String(mainTable2.id);
|
|
1209
|
+
const detailUrl = okrAbsoluteUrl(session.baseUrl, await resolver.resolve(goalId));
|
|
1210
|
+
goals.push(normalizeEbGoal(mainTable2, detailUrl));
|
|
1211
|
+
}
|
|
1212
|
+
paging.hasNext = tables.length === pageSize;
|
|
1213
|
+
}
|
|
1214
|
+
warnings.push(...resolver.warnings);
|
|
1215
|
+
return okrSuccess(
|
|
1216
|
+
"okr.list",
|
|
1217
|
+
{
|
|
1218
|
+
status: "COMPLETE",
|
|
1219
|
+
link,
|
|
1220
|
+
queryScope,
|
|
1221
|
+
period: period ? { periodType: period.periodType, periodRange: period.periodRange, periodQuarter: period.periodQuarter ?? null } : null,
|
|
1222
|
+
page: { pageNo, pageSize, ...paging },
|
|
1223
|
+
count: goals.length,
|
|
1224
|
+
goals,
|
|
1225
|
+
table: buildGoalTable(goals)
|
|
1226
|
+
},
|
|
1227
|
+
{ notes, ...warnings.length > 0 ? { warnings } : {} }
|
|
1228
|
+
);
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
async function fetchCommentCount(host, goalId) {
|
|
1232
|
+
try {
|
|
1233
|
+
const response = await host.request({
|
|
1234
|
+
method: "POST",
|
|
1235
|
+
path: "/api/goal/common/comment/commentPage",
|
|
1236
|
+
operation: "okr.get",
|
|
1237
|
+
body: { pageNo: 1, pageSize: 1, targetId: goalId, module: "goal", foldCommentList: false }
|
|
1238
|
+
});
|
|
1239
|
+
const total = response?.data?.page?.totalCount;
|
|
1240
|
+
return { totalCount: total === void 0 || total === null ? 0 : Number(total), unavailable: false };
|
|
1241
|
+
} catch {
|
|
1242
|
+
return { totalCount: null, unavailable: true };
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
var okrGet = {
|
|
1246
|
+
name: "okr.get",
|
|
1247
|
+
resource: "okr",
|
|
1248
|
+
method: "get",
|
|
1249
|
+
action: "okr.get",
|
|
1250
|
+
summary: "\u6309\u76EE\u6807 ID \u67E5\u8BE2\u5355\u4E2A\u76EE\u6807\u8BE6\u60C5\uFF1B\u6807\u51C6\u7248\u94FE\u8DEF\u4F1A\u989D\u5916\u67E5\u8BE2\u8BC4\u8BBA\u603B\u6761\u6570\u5E76\u53EA\u8FD4\u56DE\u300C\u662F\u5426\u9700\u8981\u67E5\u770B\u8BC4\u8BBA\u5185\u5BB9\u300D\u7684\u63D0\u793A\uFF0C\u4E0D\u8F93\u51FA\u8BC4\u8BBA\u6B63\u6587",
|
|
1251
|
+
capability: "okr",
|
|
1252
|
+
risk: "read",
|
|
1253
|
+
inputSchema: schemaOf(
|
|
1254
|
+
{
|
|
1255
|
+
id: SCHEMA_ID,
|
|
1256
|
+
include_comment_count: {
|
|
1257
|
+
type: "boolean",
|
|
1258
|
+
default: true,
|
|
1259
|
+
description: "\u662F\u5426\u67E5\u8BE2\u8BC4\u8BBA\u603B\u6761\u6570\uFF08\u4EC5\u6807\u51C6\u7248\u94FE\u8DEF\u751F\u6548\uFF0C\u6E90\u8D44\u6599\u8981\u6C42\u67E5\u8BE2\u8BE6\u60C5\u65F6\u6267\u884C\uFF09"
|
|
1260
|
+
}
|
|
1261
|
+
},
|
|
1262
|
+
{ required: ["id"] }
|
|
1263
|
+
),
|
|
1264
|
+
handler: async (args, { host }) => {
|
|
1265
|
+
const goalId = toIdString(args.id, "id");
|
|
1266
|
+
const { link } = await resolveLink(host);
|
|
1267
|
+
const resolver = await createDetailUrlResolver(host, link);
|
|
1268
|
+
const raw = await fetchGoalRaw(host, link, goalId);
|
|
1269
|
+
if (!raw) {
|
|
1270
|
+
throw okrValidationError("not_found", `\u672A\u67E5\u8BE2\u5230\u76EE\u6807 ${goalId}\uFF0C\u8BF7\u786E\u8BA4\u76EE\u6807 ID \u662F\u5426\u6B63\u786E\u6216\u5F53\u524D\u8D26\u53F7\u662F\u5426\u6709\u67E5\u770B\u6743\u9650`);
|
|
1271
|
+
}
|
|
1272
|
+
const session = await host.getSession();
|
|
1273
|
+
const detailUrl = okrAbsoluteUrl(session.baseUrl, await resolver.resolve(goalId));
|
|
1274
|
+
const goal = link === "standard" ? normalizeStandardGoal(raw, detailUrl, raw?.keyresultList) : normalizeEbGoal(raw, detailUrl);
|
|
1275
|
+
const notes = [];
|
|
1276
|
+
let commentSummary = null;
|
|
1277
|
+
if (link === "standard" && args.include_comment_count !== false) {
|
|
1278
|
+
const comment = await fetchCommentCount(host, goalId);
|
|
1279
|
+
if (!comment.unavailable && comment.totalCount !== null && comment.totalCount > 0) {
|
|
1280
|
+
commentSummary = {
|
|
1281
|
+
totalCount: comment.totalCount,
|
|
1282
|
+
prompt: `\u8BE5\u76EE\u6807\u4E0B\u5171\u6709${comment.totalCount}\u6761\u8BC4\u8BBA\uFF0C\u662F\u5426\u9700\u8981\u67E5\u770B\u8BC4\u8BBA\u5185\u5BB9\uFF1F`
|
|
1283
|
+
};
|
|
1284
|
+
} else if (comment.unavailable) {
|
|
1285
|
+
notes.push("comment_count_unavailable");
|
|
1286
|
+
}
|
|
1287
|
+
} else if (link === "eb") {
|
|
1288
|
+
notes.push("comment_api_unsupported_on_eb_link");
|
|
1289
|
+
}
|
|
1290
|
+
const data = {
|
|
1291
|
+
status: "COMPLETE",
|
|
1292
|
+
link,
|
|
1293
|
+
goalId,
|
|
1294
|
+
goal,
|
|
1295
|
+
...commentSummary ? { commentSummary } : {},
|
|
1296
|
+
raw
|
|
1297
|
+
};
|
|
1298
|
+
return okrSuccess(
|
|
1299
|
+
"okr.get",
|
|
1300
|
+
data,
|
|
1301
|
+
{
|
|
1302
|
+
...notes.length > 0 ? { notes } : {},
|
|
1303
|
+
...resolver.warnings.length > 0 ? { warnings: resolver.warnings } : {}
|
|
1304
|
+
}
|
|
1305
|
+
);
|
|
1306
|
+
}
|
|
1307
|
+
};
|
|
1308
|
+
var okrKrList = {
|
|
1309
|
+
name: "okr.kr.list",
|
|
1310
|
+
resource: "okr",
|
|
1311
|
+
method: "kr.list",
|
|
1312
|
+
action: "okr.kr.list",
|
|
1313
|
+
summary: "\u5206\u9875\u67E5\u8BE2\u6307\u5B9A\u76EE\u6807\u4E0B\u7684\u5173\u952E\u6210\u679C\uFF08\u4EC5 ebuilder \u94FE\u8DEF\uFF1Aokr_pageQueryGoalKeyResults\uFF09",
|
|
1314
|
+
capability: "okr",
|
|
1315
|
+
risk: "read",
|
|
1316
|
+
inputSchema: schemaOf(
|
|
1317
|
+
{
|
|
1318
|
+
object_id: SCHEMA_ID,
|
|
1319
|
+
page_no: { type: "integer", minimum: 1, default: 1 },
|
|
1320
|
+
page_size: { type: "integer", minimum: 1, maximum: 100, default: 10 }
|
|
1321
|
+
},
|
|
1322
|
+
{ required: ["object_id"] }
|
|
1323
|
+
),
|
|
1324
|
+
handler: async (args, { host }) => {
|
|
1325
|
+
const objectId = toIdString(args.object_id, "object_id");
|
|
1326
|
+
const { pageNo, pageSize } = pageOf(args);
|
|
1327
|
+
const { link } = await resolveLink(host);
|
|
1328
|
+
assertLinkSupported(
|
|
1329
|
+
link,
|
|
1330
|
+
"eb",
|
|
1331
|
+
"okr.kr.list",
|
|
1332
|
+
"e10 \u6807\u51C6\u7248\u94FE\u8DEF\u6CA1\u6709\u72EC\u7ACB\u7684\u5173\u952E\u6210\u679C\u5206\u9875\u63A5\u53E3\uFF0C\u5173\u952E\u6210\u679C\u968F\u76EE\u6807\u5217\u8868/\u8BE6\u60C5\u8FD4\u56DE\uFF08okr.list \u7684 goals[].keyresultList\u3001okr.get \u7684 goal.keyresultList\uFF09"
|
|
1333
|
+
);
|
|
1334
|
+
const session = await host.getSession();
|
|
1335
|
+
const response = await host.request({
|
|
1336
|
+
method: "POST",
|
|
1337
|
+
path: "/api/ebuilder/form/formdata/v2/getFormDataList/okr_pageQueryGoalKeyResults",
|
|
1338
|
+
operation: "okr.kr.list",
|
|
1339
|
+
body: {
|
|
1340
|
+
datajson: {
|
|
1341
|
+
mainTable: { object_id: objectId },
|
|
1342
|
+
pageInfo: { pageNo: String(pageNo), pageSize: String(pageSize) },
|
|
1343
|
+
header: { operator: session.userId }
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
});
|
|
1347
|
+
if (!isDatajsonSuccess(response)) {
|
|
1348
|
+
throw okrApiError("business_error", businessMessage(response), { response: businessMessage(response) });
|
|
1349
|
+
}
|
|
1350
|
+
const items = ebMainTables(response);
|
|
1351
|
+
return okrSuccess("okr.kr.list", {
|
|
1352
|
+
status: "COMPLETE",
|
|
1353
|
+
link,
|
|
1354
|
+
objectId,
|
|
1355
|
+
page: { pageNo, pageSize, count: items.length, hasNext: items.length === pageSize },
|
|
1356
|
+
keyresults: items
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
};
|
|
1360
|
+
var okrCommentList = {
|
|
1361
|
+
name: "okr.comment.list",
|
|
1362
|
+
resource: "okr",
|
|
1363
|
+
method: "comment.list",
|
|
1364
|
+
action: "okr.comment.list",
|
|
1365
|
+
summary: "\u5206\u9875\u67E5\u8BE2\u76EE\u6807\u8BC4\u8BBA\uFF08\u4EC5\u6807\u51C6\u7248\u94FE\u8DEF\uFF09\uFF1B\u53EA\u6709\u5728\u7528\u6237\u660E\u786E\u8981\u6C42\u67E5\u770B\u8BC4\u8BBA\u5185\u5BB9\u540E\u624D\u53EF\u8C03\u7528",
|
|
1366
|
+
capability: "okr",
|
|
1367
|
+
risk: "read",
|
|
1368
|
+
inputSchema: schemaOf(
|
|
1369
|
+
{
|
|
1370
|
+
target_id: SCHEMA_ID,
|
|
1371
|
+
page_no: { type: "integer", minimum: 1, default: 1 },
|
|
1372
|
+
page_size: { type: "integer", minimum: 1, maximum: 100, default: 10 }
|
|
1373
|
+
},
|
|
1374
|
+
{ required: ["target_id"] }
|
|
1375
|
+
),
|
|
1376
|
+
handler: async (args, { host }) => {
|
|
1377
|
+
const targetId = toIdString(args.target_id, "target_id");
|
|
1378
|
+
const { pageNo, pageSize } = pageOf(args);
|
|
1379
|
+
const { link } = await resolveLink(host);
|
|
1380
|
+
assertLinkSupported(
|
|
1381
|
+
link,
|
|
1382
|
+
"standard",
|
|
1383
|
+
"okr.comment.list",
|
|
1384
|
+
"ebuilder \u94FE\u8DEF\u6E90\u8D44\u6599\u672A\u63D0\u4F9B\u76EE\u6807\u8BC4\u8BBA\u63A5\u53E3\uFF0C\u65E0\u6CD5\u67E5\u8BE2\u8BC4\u8BBA\u5185\u5BB9"
|
|
1385
|
+
);
|
|
1386
|
+
const response = await host.request({
|
|
1387
|
+
method: "POST",
|
|
1388
|
+
path: "/api/goal/common/comment/commentPage",
|
|
1389
|
+
operation: "okr.comment.list",
|
|
1390
|
+
body: { pageNo, pageSize, targetId, module: "goal", foldCommentList: false }
|
|
1391
|
+
});
|
|
1392
|
+
const page = response?.data?.page ?? {};
|
|
1393
|
+
return okrSuccess("okr.comment.list", {
|
|
1394
|
+
status: "COMPLETE",
|
|
1395
|
+
link,
|
|
1396
|
+
targetId,
|
|
1397
|
+
page: {
|
|
1398
|
+
pageNo: page.pageNo ?? pageNo,
|
|
1399
|
+
pageSize: page.pageSize ?? pageSize,
|
|
1400
|
+
totalCount: page.totalCount ?? 0,
|
|
1401
|
+
totalPages: page.totalPages ?? null,
|
|
1402
|
+
hasNext: page.hasNext ?? false
|
|
1403
|
+
},
|
|
1404
|
+
comments: Array.isArray(page.result) ? page.result : []
|
|
1405
|
+
});
|
|
1406
|
+
}
|
|
1407
|
+
};
|
|
1408
|
+
var okrDetailLink = {
|
|
1409
|
+
name: "okr.detail.link",
|
|
1410
|
+
resource: "okr",
|
|
1411
|
+
method: "detail.link",
|
|
1412
|
+
action: "okr.detail.link",
|
|
1413
|
+
summary: "\u8FD4\u56DE\u5F53\u524D\u94FE\u8DEF\u7684\u76EE\u6807\u8BE6\u60C5\u9875\u5730\u5740\u6A21\u677F\uFF08\u6807\u51C6\u7248 /sp/goal/openDetail?id=\u76EE\u6807id\uFF1Beb \u7248 /sp/ebdfpage/card/0/\u8868\u5355id/\u76EE\u6807id\uFF09",
|
|
1414
|
+
capability: "okr",
|
|
1415
|
+
risk: "read",
|
|
1416
|
+
inputSchema: schemaOf({}),
|
|
1417
|
+
handler: async (_args, { host }) => {
|
|
1418
|
+
const { link } = await resolveLink(host);
|
|
1419
|
+
const session = await host.getSession();
|
|
1420
|
+
if (link === "standard") {
|
|
1421
|
+
return okrSuccess("okr.detail.link", {
|
|
1422
|
+
link,
|
|
1423
|
+
pathTemplate: buildStandardDetailPath("{goalId}"),
|
|
1424
|
+
urlTemplate: okrAbsoluteUrl(session.baseUrl, buildStandardDetailPath("{goalId}")),
|
|
1425
|
+
formId: null
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
const info = await resolveEbFormId(host);
|
|
1429
|
+
return okrSuccess("okr.detail.link", {
|
|
1430
|
+
link,
|
|
1431
|
+
pathTemplate: info.detailUrlTemplate,
|
|
1432
|
+
urlTemplate: okrAbsoluteUrl(session.baseUrl, info.detailUrlTemplate),
|
|
1433
|
+
formId: info.formId,
|
|
1434
|
+
formIdSource: info.source
|
|
1435
|
+
});
|
|
1436
|
+
}
|
|
1437
|
+
};
|
|
1438
|
+
var okrReadOperations = [
|
|
1439
|
+
okrVersionCheck,
|
|
1440
|
+
okrEbFormResolve,
|
|
1441
|
+
okrDetailLink,
|
|
1442
|
+
okrViewlink,
|
|
1443
|
+
okrList,
|
|
1444
|
+
okrGet,
|
|
1445
|
+
okrKrList,
|
|
1446
|
+
okrCommentList
|
|
1447
|
+
];
|
|
1448
|
+
|
|
1449
|
+
// src/shortcuts/okr/operations/write.ts
|
|
1450
|
+
var CONTINUATION_TTL_SECONDS = 600;
|
|
1451
|
+
var EB_UPDATE_KEYS = [
|
|
1452
|
+
"id",
|
|
1453
|
+
"isremind",
|
|
1454
|
+
"remind_time",
|
|
1455
|
+
"wb_state",
|
|
1456
|
+
"partners",
|
|
1457
|
+
"obj_name",
|
|
1458
|
+
"principalid",
|
|
1459
|
+
"period_quarter",
|
|
1460
|
+
"period_year",
|
|
1461
|
+
"period_type",
|
|
1462
|
+
"parent_id",
|
|
1463
|
+
"score",
|
|
1464
|
+
"category_id",
|
|
1465
|
+
"scope_id",
|
|
1466
|
+
"period_range_0",
|
|
1467
|
+
"period_range_1",
|
|
1468
|
+
"remark"
|
|
1469
|
+
];
|
|
1470
|
+
var KEYRESULT_SCHEMA = {
|
|
1471
|
+
type: "object",
|
|
1472
|
+
additionalProperties: false,
|
|
1473
|
+
properties: {
|
|
1474
|
+
name: { type: "string", minLength: 1, description: "\u5173\u952E\u6210\u679C\u540D\u79F0" },
|
|
1475
|
+
principalid: SCHEMA_PERSON_ID,
|
|
1476
|
+
target_value: { type: "number", description: "\u76EE\u6807\u503C" },
|
|
1477
|
+
weight: { type: "number", description: "\u6743\u91CD" }
|
|
1478
|
+
},
|
|
1479
|
+
required: ["name"]
|
|
1480
|
+
};
|
|
1481
|
+
var GOAL_WRITE_FIELDS = {
|
|
1482
|
+
name: { type: "string", minLength: 1, description: "\u76EE\u6807\u540D\u79F0" },
|
|
1483
|
+
period_type: SCHEMA_PERIOD_TYPE,
|
|
1484
|
+
period_range: {
|
|
1485
|
+
type: "string",
|
|
1486
|
+
minLength: 1,
|
|
1487
|
+
description: "\u5468\u671F\u8303\u56F4\uFF1A\u5E74\u5EA6/\u5B63\u5EA6\u4E3A yyyy\uFF0C\u6708\u5EA6\u4E3A yyyy-MM\uFF0C\u81EA\u5B9A\u4E49\u4E3A\u300C\u5F00\u59CB\u65E5\u671F,\u7ED3\u675F\u65E5\u671F\u300D"
|
|
1488
|
+
},
|
|
1489
|
+
period_quarter: SCHEMA_QUARTER,
|
|
1490
|
+
principalid: SCHEMA_PERSON_ID,
|
|
1491
|
+
partners: {
|
|
1492
|
+
oneOf: [SCHEMA_ID_LIST_TEXT, { type: "array", items: SCHEMA_PERSON_ID }],
|
|
1493
|
+
description: "\u53C2\u4E0E\u4EBA\u4EBA\u5458 ID\uFF08\u82F1\u6587\u9017\u53F7\u62FC\u63A5\u6216\u6570\u7EC4\uFF09"
|
|
1494
|
+
},
|
|
1495
|
+
scope_id: SCHEMA_SCOPE,
|
|
1496
|
+
scope_data_id: SCHEMA_ID,
|
|
1497
|
+
principal_dept: SCHEMA_ID,
|
|
1498
|
+
parent_id: SCHEMA_ID,
|
|
1499
|
+
category_id: { type: "string", description: "\u76EE\u6807\u5206\u7C7B id" },
|
|
1500
|
+
remark: { type: "string", description: "\u76EE\u6807\u63CF\u8FF0" },
|
|
1501
|
+
progress: { type: "number", minimum: 0, maximum: 100, description: "\u76EE\u6807\u8FDB\u5EA6" },
|
|
1502
|
+
status: {
|
|
1503
|
+
type: "string",
|
|
1504
|
+
enum: ["0", "1"],
|
|
1505
|
+
description: "\u6807\u51C6\u7248\u65B0\u5EFA/\u7F16\u8F91\u72B6\u6001\uFF1A0-\u4FDD\u5B58\u8349\u7A3F 1-\u6B63\u5F0F\u63D0\u4EA4\uFF08\u9ED8\u8BA4 0\uFF09"
|
|
1506
|
+
},
|
|
1507
|
+
m_status: {
|
|
1508
|
+
type: "string",
|
|
1509
|
+
enum: ["1", "2", "3", "4", "5"],
|
|
1510
|
+
description: "ebuilder \u76EE\u6807\u8FDB\u5C55\uFF1A1-\u8FDB\u884C\u4E2D 2-\u5DF2\u5B8C\u6210 3-\u5DF2\u64A4\u9500 4-\u5BA1\u6279\u4E2D 5-\u672A\u5F00\u59CB\uFF08\u65B0\u5EFA\u9ED8\u8BA4 1\uFF09"
|
|
1511
|
+
},
|
|
1512
|
+
wb_state: { type: "string", enum: ["1", "2", "3"], description: "ebuilder \u76EE\u6807\u7D27\u6025\u72B6\u6001\uFF1A1-\u6B63\u5E38 2-\u7D27\u6025 3-\u975E\u5E38\u7D27\u6025" },
|
|
1513
|
+
keyresult_list: {
|
|
1514
|
+
type: "array",
|
|
1515
|
+
items: KEYRESULT_SCHEMA,
|
|
1516
|
+
description: "\u968F\u76EE\u6807\u4E00\u8D77\u521B\u5EFA\u7684\u5173\u952E\u6210\u679C\uFF08\u4EC5\u6807\u51C6\u7248\u94FE\u8DEF\uFF09"
|
|
1517
|
+
}
|
|
1518
|
+
};
|
|
1519
|
+
function pickKeys(source, keys) {
|
|
1520
|
+
const result = {};
|
|
1521
|
+
for (const key of keys) {
|
|
1522
|
+
if (source[key] !== void 0 && source[key] !== null && source[key] !== "") result[key] = source[key];
|
|
1523
|
+
}
|
|
1524
|
+
return result;
|
|
1525
|
+
}
|
|
1526
|
+
function buildEbCreateMainTable(args, period, principalid) {
|
|
1527
|
+
const scopeId = args.scope_id === void 0 ? "1" : String(args.scope_id);
|
|
1528
|
+
const principalDept = args.principal_dept === void 0 ? void 0 : toIdString(args.principal_dept, "principal_dept");
|
|
1529
|
+
if (scopeId === "2" && !principalDept) {
|
|
1530
|
+
throw okrValidationError(
|
|
1531
|
+
"principal_dept_required",
|
|
1532
|
+
"ebuilder \u94FE\u8DEF\u521B\u5EFA\u90E8\u95E8\u76EE\u6807\uFF08scope_id=2\uFF09\u5FC5\u987B\u63D0\u4F9B principal_dept\uFF08\u8D23\u4EFB\u4EBA\u90E8\u95E8 id\uFF09"
|
|
1533
|
+
);
|
|
1534
|
+
}
|
|
1535
|
+
return compact({
|
|
1536
|
+
...ebPeriodFields(period),
|
|
1537
|
+
obj_name: String(args.name),
|
|
1538
|
+
scope_id: scopeId,
|
|
1539
|
+
principalid,
|
|
1540
|
+
...principalDept ? { principal_dept: principalDept } : {},
|
|
1541
|
+
...args.partners === void 0 ? {} : { partners: toPersonIdListText(args.partners, "partners") },
|
|
1542
|
+
...args.parent_id === void 0 ? {} : { parent_id: toIdString(args.parent_id, "parent_id") },
|
|
1543
|
+
...args.category_id === void 0 ? {} : { category_id: String(args.category_id) },
|
|
1544
|
+
// 源资料默认值:目标进展默认为进行中(m_status=1),目标进度默认 0。
|
|
1545
|
+
m_status: args.m_status === void 0 ? "1" : String(args.m_status),
|
|
1546
|
+
progress: args.progress === void 0 ? 0 : Number(args.progress),
|
|
1547
|
+
...args.wb_state === void 0 ? {} : { wb_state: String(args.wb_state) }
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
function standardBodyFromCurrent(current) {
|
|
1551
|
+
return compact({
|
|
1552
|
+
name: current?.name,
|
|
1553
|
+
scopeId: optionValue(current?.scopeId) ?? (current?.scopeId === void 0 ? void 0 : String(current.scopeId)),
|
|
1554
|
+
scopeDataId: current?.scopeDataId === void 0 ? void 0 : String(current.scopeDataId),
|
|
1555
|
+
periodType: optionValue(current?.periodType) ?? (current?.periodType === void 0 ? void 0 : String(current.periodType)),
|
|
1556
|
+
periodRange: current?.periodRange === void 0 ? void 0 : String(current.periodRange),
|
|
1557
|
+
periodQuarter: optionValue(current?.periodQuarter) ?? (current?.periodQuarter === void 0 ? void 0 : String(current.periodQuarter)),
|
|
1558
|
+
principalid: current?.principalid === void 0 ? void 0 : String(current.principalid),
|
|
1559
|
+
partners: current?.partners === void 0 ? void 0 : String(current.partners),
|
|
1560
|
+
remark: current?.remark,
|
|
1561
|
+
parentId: current?.parentId === void 0 ? void 0 : String(current.parentId)
|
|
1562
|
+
});
|
|
1563
|
+
}
|
|
1564
|
+
function buildStandardGoalBody(args, mode, host) {
|
|
1565
|
+
const current = host.current ?? {};
|
|
1566
|
+
const base = standardBodyFromCurrent(current);
|
|
1567
|
+
const scopeId = args.scope_id === void 0 ? base.scopeId === void 0 ? "1" : String(base.scopeId) : String(args.scope_id);
|
|
1568
|
+
const scopeDataId = args.scope_data_id === void 0 ? base.scopeDataId === void 0 ? void 0 : String(base.scopeDataId) : toIdString(args.scope_data_id, "scope_data_id");
|
|
1569
|
+
if (scopeId === "2" && !scopeDataId) {
|
|
1570
|
+
throw okrValidationError(
|
|
1571
|
+
"scope_data_id_required",
|
|
1572
|
+
"\u6807\u51C6\u7248\u94FE\u8DEF\u521B\u5EFA/\u7F16\u8F91\u90E8\u95E8\u76EE\u6807\uFF08scope_id=2\uFF09\u5FC5\u987B\u63D0\u4F9B scope_data_id\uFF08\u90E8\u95E8 id\uFF09"
|
|
1573
|
+
);
|
|
1574
|
+
}
|
|
1575
|
+
const periodType = host.period ? host.period.periodType : base.periodType === void 0 ? void 0 : String(base.periodType);
|
|
1576
|
+
if (!periodType) {
|
|
1577
|
+
throw okrValidationError("period_type_invalid", "\u65E0\u6CD5\u4ECE\u5F53\u524D\u76EE\u6807\u8FD8\u539F\u5468\u671F\u7C7B\u578B\uFF0C\u8BF7\u663E\u5F0F\u63D0\u4F9B period_type \u4E0E period_range");
|
|
1578
|
+
}
|
|
1579
|
+
const periodRange = host.period ? host.period.periodRange : base.periodRange === void 0 ? void 0 : String(base.periodRange);
|
|
1580
|
+
if (!periodRange) {
|
|
1581
|
+
throw okrValidationError("period_range_required", "\u65E0\u6CD5\u4ECE\u5F53\u524D\u76EE\u6807\u8FD8\u539F\u5468\u671F\u8303\u56F4\uFF0C\u8BF7\u663E\u5F0F\u63D0\u4F9B period_type \u4E0E period_range");
|
|
1582
|
+
}
|
|
1583
|
+
const periodQuarter = periodType === "2" ? host.period?.periodQuarter ?? (base.periodQuarter === void 0 ? void 0 : String(base.periodQuarter)) : void 0;
|
|
1584
|
+
if (periodType === "2" && !periodQuarter) {
|
|
1585
|
+
throw okrValidationError("period_quarter_invalid", "\u5B63\u5EA6\u76EE\u6807\u5FC5\u987B\u63D0\u4F9B period_quarter\uFF081/2/3/4\uFF09");
|
|
1586
|
+
}
|
|
1587
|
+
const keyresultList = Array.isArray(args.keyresult_list) ? args.keyresult_list.map((item) => compact({
|
|
1588
|
+
name: String(item.name),
|
|
1589
|
+
...item.principalid === void 0 ? {} : { principalid: toPersonIdString(item.principalid, "keyresult_list[].principalid") },
|
|
1590
|
+
weight: item.weight === void 0 ? "0" : String(item.weight),
|
|
1591
|
+
...item.target_value === void 0 ? {} : { targetValue: item.target_value }
|
|
1592
|
+
})) : void 0;
|
|
1593
|
+
let status;
|
|
1594
|
+
if (args.status === void 0) {
|
|
1595
|
+
if (mode === "update") {
|
|
1596
|
+
throw okrValidationError(
|
|
1597
|
+
"status_required",
|
|
1598
|
+
"\u6807\u51C6\u7248\u7F16\u8F91\u76EE\u6807\u5FC5\u987B\u663E\u5F0F\u4F20 status\uFF080-\u4FDD\u5B58\u8349\u7A3F 1-\u6B63\u5F0F\u63D0\u4EA4\uFF09\uFF0C\u907F\u514D\u628A\u6B63\u5F0F\u76EE\u6807\u56DE\u9000\u4E3A\u8349\u7A3F"
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1601
|
+
status = "0";
|
|
1602
|
+
} else {
|
|
1603
|
+
status = String(args.status);
|
|
1604
|
+
}
|
|
1605
|
+
return buildStandardSaveBody({
|
|
1606
|
+
...host.goalId ? { goalId: host.goalId } : {},
|
|
1607
|
+
name: args.name === void 0 ? String(base.name ?? "") : String(args.name),
|
|
1608
|
+
scopeId,
|
|
1609
|
+
...scopeDataId ? { scopeDataId } : {},
|
|
1610
|
+
periodType,
|
|
1611
|
+
periodRange,
|
|
1612
|
+
...periodQuarter ? { periodQuarter } : {},
|
|
1613
|
+
principalid: args.principalid === void 0 ? host.principalid : toPersonIdString(args.principalid, "principalid"),
|
|
1614
|
+
...args.partners === void 0 ? base.partners === void 0 ? {} : { partners: String(base.partners) } : { partners: toPersonIdListText(args.partners, "partners") },
|
|
1615
|
+
...args.remark === void 0 ? base.remark === void 0 ? {} : { remark: String(base.remark) } : { remark: String(args.remark) },
|
|
1616
|
+
...keyresultList ? { keyresultList } : {},
|
|
1617
|
+
status,
|
|
1618
|
+
parentId: args.parent_id === void 0 ? base.parentId === void 0 ? "0" : String(base.parentId) : toIdString(args.parent_id, "parent_id")
|
|
1619
|
+
});
|
|
1620
|
+
}
|
|
1621
|
+
function goalPreview(link, body) {
|
|
1622
|
+
if (link === "standard") {
|
|
1623
|
+
return {
|
|
1624
|
+
\u76EE\u6807\u540D\u79F0: body.name,
|
|
1625
|
+
\u76EE\u6807\u7EA7\u522B: body.scopeId === "2" ? "\u90E8\u95E8\u76EE\u6807" : "\u4E2A\u4EBA\u76EE\u6807",
|
|
1626
|
+
\u5468\u671F\u7C7B\u578B: body.periodType,
|
|
1627
|
+
\u5468\u671F\u8303\u56F4: body.periodRange,
|
|
1628
|
+
\u8D23\u4EFB\u4EBA: body.principalid,
|
|
1629
|
+
\u53C2\u4E0E\u4EBA: body.partners ?? null,
|
|
1630
|
+
\u72B6\u6001: body.status === "1" ? "\u6B63\u5F0F\u63D0\u4EA4" : "\u4FDD\u5B58\u8349\u7A3F",
|
|
1631
|
+
\u4E0A\u7EA7\u76EE\u6807: body.parentId ?? "0",
|
|
1632
|
+
\u63CF\u8FF0: body.remark ?? null
|
|
1633
|
+
};
|
|
1634
|
+
}
|
|
1635
|
+
return {
|
|
1636
|
+
\u76EE\u6807\u540D\u79F0: body.obj_name,
|
|
1637
|
+
\u76EE\u6807\u7EA7\u522B: body.scope_id === "2" ? "\u90E8\u95E8\u76EE\u6807" : "\u4E2A\u4EBA\u76EE\u6807",
|
|
1638
|
+
\u5468\u671F\u7C7B\u578B: body.period_type,
|
|
1639
|
+
\u5468\u671F\u8303\u56F4: `${body.period_range_0 ?? ""} ~ ${body.period_range_1 ?? ""}`,
|
|
1640
|
+
\u8D23\u4EFB\u4EBA: body.principalid,
|
|
1641
|
+
\u53C2\u4E0E\u4EBA: body.partners ?? null,
|
|
1642
|
+
\u8FDB\u5C55: body.m_status ?? null,
|
|
1643
|
+
\u8FDB\u5EA6: body.progress ?? null,
|
|
1644
|
+
\u7D27\u6025\u72B6\u6001: body.wb_state ?? null
|
|
1645
|
+
};
|
|
1646
|
+
}
|
|
1647
|
+
async function buildGoalPayload(args, env, mode) {
|
|
1648
|
+
const { host } = env;
|
|
1649
|
+
const { link } = await resolveLink(host);
|
|
1650
|
+
const session = await host.getSession();
|
|
1651
|
+
const notes = [];
|
|
1652
|
+
const warnings = [];
|
|
1653
|
+
const goalId = mode === "update" ? toIdString(args.id, "id") : null;
|
|
1654
|
+
const hasPeriod = args.period_type !== void 0 || args.period_range !== void 0;
|
|
1655
|
+
let period = null;
|
|
1656
|
+
if (hasPeriod) {
|
|
1657
|
+
if (mode === "create" && (args.period_type === void 0 || args.period_range === void 0)) {
|
|
1658
|
+
throw okrValidationError("period_required", "okr.create \u5FC5\u987B\u540C\u65F6\u4F20 period_type \u4E0E period_range");
|
|
1659
|
+
}
|
|
1660
|
+
period = resolvePeriod(args);
|
|
1661
|
+
} else if (mode === "create") {
|
|
1662
|
+
throw okrValidationError("period_required", "okr.create \u5FC5\u987B\u540C\u65F6\u4F20 period_type \u4E0E period_range");
|
|
1663
|
+
}
|
|
1664
|
+
if (mode === "create" && (args.name === void 0 || String(args.name).trim() === "")) {
|
|
1665
|
+
throw okrValidationError("name_required", "name\uFF08\u76EE\u6807\u540D\u79F0\uFF09\u5FC5\u586B");
|
|
1666
|
+
}
|
|
1667
|
+
const current = mode === "update" ? await fetchGoalRaw(host, link, goalId) : null;
|
|
1668
|
+
if (mode === "update" && !current) {
|
|
1669
|
+
throw okrValidationError("not_found", `\u672A\u67E5\u8BE2\u5230\u76EE\u6807 ${goalId}\uFF0C\u65E0\u6CD5\u7F16\u8F91\uFF1B\u8BF7\u786E\u8BA4\u76EE\u6807 ID \u6216\u67E5\u770B\u6743\u9650`);
|
|
1670
|
+
}
|
|
1671
|
+
const principalid = args.principalid === void 0 ? mode === "update" ? goalPrincipalId(current, link) ?? session.userId : session.userId : toPersonIdString(args.principalid, "principalid");
|
|
1672
|
+
if (link === "standard") {
|
|
1673
|
+
if (args.m_status !== void 0 || args.wb_state !== void 0 || args.principal_dept !== void 0) {
|
|
1674
|
+
notes.push("eb_only_fields_ignored:m_status/wb_state/principal_dept");
|
|
1675
|
+
}
|
|
1676
|
+
const body = buildStandardGoalBody(args, mode, { current, principalid, period, ...goalId ? { goalId } : {} });
|
|
1677
|
+
return {
|
|
1678
|
+
link,
|
|
1679
|
+
endpoint: mode === "create" ? "standard-create" : "standard-update",
|
|
1680
|
+
goalId,
|
|
1681
|
+
body,
|
|
1682
|
+
preview: goalPreview(link, body),
|
|
1683
|
+
notes,
|
|
1684
|
+
warnings
|
|
1685
|
+
};
|
|
1686
|
+
}
|
|
1687
|
+
if (args.keyresult_list !== void 0) {
|
|
1688
|
+
notes.push("standard_only_fields_ignored:keyresult_list");
|
|
1689
|
+
}
|
|
1690
|
+
let mainTable;
|
|
1691
|
+
if (mode === "create") {
|
|
1692
|
+
mainTable = buildEbCreateMainTable(args, period, principalid);
|
|
1693
|
+
} else {
|
|
1694
|
+
const base = pickKeys(current, EB_UPDATE_KEYS);
|
|
1695
|
+
mainTable = compact({
|
|
1696
|
+
...base,
|
|
1697
|
+
id: goalId,
|
|
1698
|
+
...hasPeriod ? ebPeriodFields(period) : {},
|
|
1699
|
+
...args.name === void 0 ? {} : { obj_name: String(args.name) },
|
|
1700
|
+
...args.scope_id === void 0 ? {} : { scope_id: String(args.scope_id) },
|
|
1701
|
+
principalid,
|
|
1702
|
+
...args.partners === void 0 ? {} : { partners: toPersonIdListText(args.partners, "partners") },
|
|
1703
|
+
...args.parent_id === void 0 ? {} : { parent_id: toIdString(args.parent_id, "parent_id") },
|
|
1704
|
+
...args.category_id === void 0 ? {} : { category_id: String(args.category_id) },
|
|
1705
|
+
...args.remark === void 0 ? {} : { remark: String(args.remark) },
|
|
1706
|
+
...args.wb_state === void 0 ? {} : { wb_state: String(args.wb_state) }
|
|
1707
|
+
});
|
|
1708
|
+
}
|
|
1709
|
+
return {
|
|
1710
|
+
link,
|
|
1711
|
+
endpoint: mode === "create" ? "eb-create" : "eb-update",
|
|
1712
|
+
goalId,
|
|
1713
|
+
body: mainTable,
|
|
1714
|
+
preview: goalPreview(link, mainTable),
|
|
1715
|
+
notes,
|
|
1716
|
+
warnings
|
|
1717
|
+
};
|
|
1718
|
+
}
|
|
1719
|
+
var GOAL_PREPARE_SCHEMA = schemaOf({ ...GOAL_WRITE_FIELDS }, { required: ["name", "period_type", "period_range"] });
|
|
1720
|
+
var GOAL_UPDATE_PREPARE_SCHEMA = schemaOf({ id: SCHEMA_ID, ...GOAL_WRITE_FIELDS }, { required: ["id"] });
|
|
1721
|
+
var GOAL_APPLY_EXTRA = { confirm: { const: true }, continuation: { type: "string", minLength: 1 } };
|
|
1722
|
+
function standardSavePath(endpoint) {
|
|
1723
|
+
return endpoint === "standard-create" ? "/api/workrelate/goal/create" : "/api/workrelate/goal/update";
|
|
1724
|
+
}
|
|
1725
|
+
function ebSavePath(endpoint) {
|
|
1726
|
+
return endpoint === "eb-create" ? "/api/ebuilder/form/formdata/v2/saveFormData/okr_createGoal" : "/api/ebuilder/form/formdata/v2/updateFormData/okr_updateGoal";
|
|
1727
|
+
}
|
|
1728
|
+
async function submitGoalWrite(env, payload, action) {
|
|
1729
|
+
const { host } = env;
|
|
1730
|
+
const session = await host.getSession();
|
|
1731
|
+
let response;
|
|
1732
|
+
try {
|
|
1733
|
+
if (payload.link === "standard") {
|
|
1734
|
+
response = await host.request({
|
|
1735
|
+
method: "POST",
|
|
1736
|
+
path: standardSavePath(payload.endpoint),
|
|
1737
|
+
operation: action,
|
|
1738
|
+
body: payload.body
|
|
1739
|
+
});
|
|
1740
|
+
if (response?.status === false || response?.status === "false") {
|
|
1741
|
+
throw okrApiError("business_error", businessMessage(response), { response: businessMessage(response) });
|
|
1742
|
+
}
|
|
1743
|
+
} else {
|
|
1744
|
+
response = await host.request({
|
|
1745
|
+
method: "POST",
|
|
1746
|
+
path: ebSavePath(payload.endpoint),
|
|
1747
|
+
operation: action,
|
|
1748
|
+
body: {
|
|
1749
|
+
datajson: {
|
|
1750
|
+
datas: [{ mainTable: payload.body }],
|
|
1751
|
+
header: { operator: session.userId }
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
});
|
|
1755
|
+
if (!isDatajsonSuccess(response)) {
|
|
1756
|
+
throw okrApiError("business_error", businessMessage(response), { response: businessMessage(response) });
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
} catch (error) {
|
|
1760
|
+
if (error?.type === "network") {
|
|
1761
|
+
throw okrPartialError(
|
|
1762
|
+
"\u76EE\u6807\u5199\u5165\u8BF7\u6C42\u53D1\u9001\u540E\u8FDE\u63A5\u4E2D\u65AD\uFF0C\u662F\u5426\u5DF2\u5199\u5165\u4E0D\u786E\u5B9A\uFF0C\u7981\u6B62\u81EA\u52A8\u91CD\u8BD5\uFF0C\u8BF7\u901A\u8FC7 okr.get \u590D\u6838",
|
|
1763
|
+
{ attempted: { endpoint: payload.endpoint, goalId: payload.goalId, preview: payload.preview } },
|
|
1764
|
+
{ stage: payload.endpoint }
|
|
1765
|
+
);
|
|
1766
|
+
}
|
|
1767
|
+
throw error;
|
|
1768
|
+
}
|
|
1769
|
+
let writtenId = payload.goalId;
|
|
1770
|
+
if (!writtenId && payload.link === "standard") {
|
|
1771
|
+
const rawId = response?.data?.id;
|
|
1772
|
+
writtenId = rawId === void 0 || rawId === null || rawId === "" ? null : String(rawId);
|
|
1773
|
+
}
|
|
1774
|
+
if (!writtenId && payload.link === "eb") {
|
|
1775
|
+
const dataIds = response?.datajson?.dataIds;
|
|
1776
|
+
if (Array.isArray(dataIds) && dataIds.length > 0 && dataIds[0] !== void 0 && dataIds[0] !== null) {
|
|
1777
|
+
writtenId = String(dataIds[0]);
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
const resolver = await createDetailUrlResolver(host, payload.link);
|
|
1781
|
+
const detailPath = await resolver.resolve(writtenId);
|
|
1782
|
+
const detailUrl = okrAbsoluteUrl(session.baseUrl, detailPath);
|
|
1783
|
+
return okrSuccess(
|
|
1784
|
+
action,
|
|
1785
|
+
{
|
|
1786
|
+
status: "COMPLETE",
|
|
1787
|
+
link: payload.link,
|
|
1788
|
+
endpoint: payload.endpoint,
|
|
1789
|
+
goalId: writtenId,
|
|
1790
|
+
path: detailPath,
|
|
1791
|
+
detailUrl,
|
|
1792
|
+
anchor: "\u67E5\u770B\u76EE\u6807\u8BE6\u60C5",
|
|
1793
|
+
result: response
|
|
1794
|
+
},
|
|
1795
|
+
{
|
|
1796
|
+
...payload.notes.length > 0 ? { notes: payload.notes } : {},
|
|
1797
|
+
...resolver.warnings.length > 0 ? { warnings: resolver.warnings } : {}
|
|
1798
|
+
}
|
|
1799
|
+
);
|
|
1800
|
+
}
|
|
1801
|
+
function goalWriteDefinitions(mode) {
|
|
1802
|
+
const singular = mode === "create" ? "create" : "update";
|
|
1803
|
+
const label = mode === "create" ? "\u65B0\u5EFA\u76EE\u6807" : "\u7F16\u8F91\u76EE\u6807";
|
|
1804
|
+
const prepareName = `okr.${singular}.prepare`;
|
|
1805
|
+
const applyName = `okr.${singular}.apply`;
|
|
1806
|
+
const prepare = {
|
|
1807
|
+
name: prepareName,
|
|
1808
|
+
resource: "okr",
|
|
1809
|
+
method: `${singular}.prepare`,
|
|
1810
|
+
action: prepareName,
|
|
1811
|
+
summary: mode === "create" ? "\u51C6\u5907\u65B0\u5EFA\u76EE\u6807\uFF1A\u5F52\u4E00\u5316\u5468\u671F/\u4EBA\u5458/\u9ED8\u8BA4\u503C\uFF08\u8FDB\u5C55\u9ED8\u8BA4\u8FDB\u884C\u4E2D\u3001\u8FDB\u5EA6\u9ED8\u8BA4 0\u3001\u8D23\u4EFB\u4EBA\u9ED8\u8BA4\u5F53\u524D\u7528\u6237\uFF09\uFF0C\u751F\u6210\u786E\u8BA4\u9884\u89C8\uFF0C\u4E0D\u5199\u5165" : "\u51C6\u5907\u7F16\u8F91\u76EE\u6807\uFF1A\u5148\u67E5\u8BE2\u5F53\u524D\u76EE\u6807\u8BE6\u60C5\u5E76\u5408\u5E76\u4FEE\u6539\uFF08\u5168\u91CF\u8986\u76D6\uFF09\uFF0C\u751F\u6210\u786E\u8BA4\u9884\u89C8\uFF0C\u4E0D\u5199\u5165",
|
|
1812
|
+
capability: "okr",
|
|
1813
|
+
risk: "read-before-write",
|
|
1814
|
+
requiresConfirmation: true,
|
|
1815
|
+
inputSchema: mode === "create" ? GOAL_PREPARE_SCHEMA : GOAL_UPDATE_PREPARE_SCHEMA,
|
|
1816
|
+
handler: async (args, env) => {
|
|
1817
|
+
const payload = await buildGoalPayload(args, env, mode);
|
|
1818
|
+
const session = await env.host.getSession();
|
|
1819
|
+
const token = await env.continuation.issue(
|
|
1820
|
+
{
|
|
1821
|
+
operation: applyName,
|
|
1822
|
+
baseUrl: session.baseUrl,
|
|
1823
|
+
profile: session.profile,
|
|
1824
|
+
userId: session.userId,
|
|
1825
|
+
link: payload.link,
|
|
1826
|
+
endpoint: payload.endpoint,
|
|
1827
|
+
goalId: payload.goalId,
|
|
1828
|
+
payload: payload.body,
|
|
1829
|
+
fingerprint: fingerprint(payload.body)
|
|
1830
|
+
},
|
|
1831
|
+
CONTINUATION_TTL_SECONDS * 1e3
|
|
1832
|
+
);
|
|
1833
|
+
return okrSuccess(
|
|
1834
|
+
prepareName,
|
|
1835
|
+
{
|
|
1836
|
+
status: "AWAITING_CONFIRMATION",
|
|
1837
|
+
link: payload.link,
|
|
1838
|
+
endpoint: payload.endpoint,
|
|
1839
|
+
goalId: payload.goalId,
|
|
1840
|
+
preview: payload.preview,
|
|
1841
|
+
continuation: token,
|
|
1842
|
+
expiresInSeconds: CONTINUATION_TTL_SECONDS
|
|
1843
|
+
},
|
|
1844
|
+
{
|
|
1845
|
+
...payload.notes.length > 0 ? { notes: payload.notes } : {},
|
|
1846
|
+
...payload.warnings.length > 0 ? { warnings: payload.warnings } : {}
|
|
1847
|
+
}
|
|
1848
|
+
);
|
|
1849
|
+
}
|
|
1850
|
+
};
|
|
1851
|
+
const applyFields = mode === "create" ? { ...GOAL_WRITE_FIELDS, ...GOAL_APPLY_EXTRA } : { id: SCHEMA_ID, ...GOAL_WRITE_FIELDS, ...GOAL_APPLY_EXTRA };
|
|
1852
|
+
const apply = {
|
|
1853
|
+
name: applyName,
|
|
1854
|
+
resource: "okr",
|
|
1855
|
+
method: `${singular}.apply`,
|
|
1856
|
+
action: applyName,
|
|
1857
|
+
summary: `\u63D0\u4EA4${label}\uFF1B\u5FC5\u987B\u5728\u7528\u6237\u660E\u786E\u786E\u8BA4\u540E\u8C03\u7528\uFF0C\u4E14\u8981\u6C42 prepare \u8FD4\u56DE\u7684 continuation`,
|
|
1858
|
+
capability: "okr",
|
|
1859
|
+
risk: "high-risk-write",
|
|
1860
|
+
requiresConfirmation: true,
|
|
1861
|
+
inputSchema: schemaOf(applyFields, { required: mode === "create" ? ["confirm", "continuation"] : ["id", "confirm", "continuation"] }),
|
|
1862
|
+
handler: async (args, env) => {
|
|
1863
|
+
const lease = await ensureConfirmLease(args, applyName, env);
|
|
1864
|
+
if (mode === "update") {
|
|
1865
|
+
const goalId = toIdString(args.id, "id");
|
|
1866
|
+
if (String(lease.goalId ?? "") !== goalId) {
|
|
1867
|
+
throw okrValidationError("target_changed", "\u76EE\u6807 ID \u4E0E prepare \u65F6\u7684\u5FEB\u7167\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C prepare");
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
const payload = {
|
|
1871
|
+
link: lease.link,
|
|
1872
|
+
endpoint: lease.endpoint,
|
|
1873
|
+
goalId: lease.goalId ?? null,
|
|
1874
|
+
body: lease.payload ?? {},
|
|
1875
|
+
preview: {},
|
|
1876
|
+
notes: [],
|
|
1877
|
+
warnings: []
|
|
1878
|
+
};
|
|
1879
|
+
if (lease.fingerprint !== fingerprint(payload.body)) {
|
|
1880
|
+
throw okrValidationError("target_changed", "\u5199\u5165\u5185\u5BB9\u4E0E prepare \u65F6\u7684\u5FEB\u7167\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C prepare");
|
|
1881
|
+
}
|
|
1882
|
+
return submitGoalWrite(env, payload, applyName);
|
|
1883
|
+
}
|
|
1884
|
+
};
|
|
1885
|
+
return [prepare, apply];
|
|
1886
|
+
}
|
|
1887
|
+
var KR_WRITE_FIELDS = {
|
|
1888
|
+
kr_id: { ...SCHEMA_ID, description: "\u5173\u952E\u6210\u679C ID\uFF1B\u4E0D\u4F20\u4E3A\u65B0\u5EFA\uFF0C\u4F20\u4E86\u4E3A\u4FEE\u6539" },
|
|
1889
|
+
object_id: { ...SCHEMA_ID, description: "\u6240\u5C5E\u76EE\u6807 ID\uFF08ebuilder \u94FE\u8DEF\u5FC5\u586B\uFF09" },
|
|
1890
|
+
name: { type: "string", minLength: 1, description: "\u5173\u952E\u6210\u679C\u540D\u79F0" },
|
|
1891
|
+
principalid: SCHEMA_PERSON_ID,
|
|
1892
|
+
participants: {
|
|
1893
|
+
oneOf: [SCHEMA_ID_LIST_TEXT, { type: "array", items: SCHEMA_PERSON_ID }],
|
|
1894
|
+
description: "\u53C2\u4E0E\u4EBA\u4EBA\u5458 ID\uFF08\u4EC5\u6807\u51C6\u7248\u94FE\u8DEF\uFF09"
|
|
1895
|
+
},
|
|
1896
|
+
target_value: { type: "number", description: "\u76EE\u6807\u503C" },
|
|
1897
|
+
actual_value: { type: "number", description: "\u5B9E\u9645\u503C" },
|
|
1898
|
+
weight: { type: "number", description: "\u6743\u91CD" },
|
|
1899
|
+
progress: { type: "number", minimum: 0, maximum: 100, description: "\u8FDB\u5EA6" },
|
|
1900
|
+
score: { type: "number", description: "\u5206\u6570" },
|
|
1901
|
+
range: {
|
|
1902
|
+
oneOf: [
|
|
1903
|
+
{ type: "array", items: SCHEMA_DATE, minItems: 2, maxItems: 2 },
|
|
1904
|
+
{ type: "string", pattern: "^\\d{4}-\\d{2}-\\d{2},\\d{4}-\\d{2}-\\d{2}$" }
|
|
1905
|
+
],
|
|
1906
|
+
description: "\u8D77\u6B62\u65E5\u671F [\u5F00\u59CB, \u7ED3\u675F]\uFF0Cyyyy-MM-dd"
|
|
1907
|
+
},
|
|
1908
|
+
kr_unit: { type: "string", description: "\u5355\u4F4D\uFF08\u4EC5 ebuilder \u94FE\u8DEF\uFF09" },
|
|
1909
|
+
confidence: { type: "number", description: "\u4FE1\u5FC3\u6307\u6570\uFF08\u4EC5 ebuilder \u94FE\u8DEF\uFF09" },
|
|
1910
|
+
risk: { type: "string", enum: ["1", "2", "3"], description: "\u98CE\u9669\u6307\u6570\uFF1A1-\u6B63\u5E38 2-\u6709\u98CE\u9669 3-\u5DF2\u5EF6\u671F\uFF08\u4EC5 ebuilder \u94FE\u8DEF\uFF09" }
|
|
1911
|
+
};
|
|
1912
|
+
function resolveDateRange(value) {
|
|
1913
|
+
if (value === void 0 || value === null || value === "") return null;
|
|
1914
|
+
const parts = Array.isArray(value) ? value.map((item) => String(item)) : String(value).split(",");
|
|
1915
|
+
if (parts.length !== 2 || !/^\d{4}-\d{2}-\d{2}$/.test(parts[0]) || !/^\d{4}-\d{2}-\d{2}$/.test(parts[1])) {
|
|
1916
|
+
throw okrValidationError("range_invalid", "range \u5FC5\u987B\u662F [\u5F00\u59CB\u65E5\u671F, \u7ED3\u675F\u65E5\u671F]\uFF08yyyy-MM-dd\uFF09\u6216\u300C\u5F00\u59CB\u65E5\u671F,\u7ED3\u675F\u65E5\u671F\u300D\u5B57\u7B26\u4E32");
|
|
1917
|
+
}
|
|
1918
|
+
if (parts[0] > parts[1]) {
|
|
1919
|
+
throw okrValidationError("range_invalid", "range \u7684\u5F00\u59CB\u65E5\u671F\u4E0D\u80FD\u665A\u4E8E\u7ED3\u675F\u65E5\u671F");
|
|
1920
|
+
}
|
|
1921
|
+
return [parts[0], parts[1]];
|
|
1922
|
+
}
|
|
1923
|
+
async function buildKrPayload(args, env) {
|
|
1924
|
+
const { host } = env;
|
|
1925
|
+
const { link } = await resolveLink(host);
|
|
1926
|
+
const session = await host.getSession();
|
|
1927
|
+
const notes = [];
|
|
1928
|
+
const krId = args.kr_id === void 0 ? null : toIdString(args.kr_id, "kr_id");
|
|
1929
|
+
const name = String(args.name ?? "").trim();
|
|
1930
|
+
if (!name) throw okrValidationError("name_required", "name\uFF08\u5173\u952E\u6210\u679C\u540D\u79F0\uFF09\u5FC5\u586B");
|
|
1931
|
+
const principalid = args.principalid === void 0 ? session.userId : toPersonIdString(args.principalid, "principalid");
|
|
1932
|
+
const range = resolveDateRange(args.range);
|
|
1933
|
+
if (link === "standard") {
|
|
1934
|
+
for (const field of ["kr_unit", "confidence", "risk"]) {
|
|
1935
|
+
if (args[field] !== void 0) notes.push(`eb_only_fields_ignored:${field}`);
|
|
1936
|
+
}
|
|
1937
|
+
const objectId = toIdString(args.object_id, "object_id");
|
|
1938
|
+
const body = compact({
|
|
1939
|
+
baseInfo: compact({
|
|
1940
|
+
...krId ? { id: krId } : {},
|
|
1941
|
+
objectId,
|
|
1942
|
+
name,
|
|
1943
|
+
principalId: principalid,
|
|
1944
|
+
...args.participants === void 0 ? {} : { participants: toPersonIdListText(args.participants, "participants") },
|
|
1945
|
+
...args.target_value === void 0 ? {} : { targetValue: args.target_value },
|
|
1946
|
+
...args.actual_value === void 0 ? {} : { actualValue: args.actual_value },
|
|
1947
|
+
...args.weight === void 0 ? {} : { weight: args.weight },
|
|
1948
|
+
...args.progress === void 0 ? {} : { progress: args.progress },
|
|
1949
|
+
...args.score === void 0 ? {} : { score: args.score },
|
|
1950
|
+
...range ? { range } : {}
|
|
1951
|
+
})
|
|
1952
|
+
});
|
|
1953
|
+
return {
|
|
1954
|
+
link,
|
|
1955
|
+
endpoint: "standard-kr-save",
|
|
1956
|
+
body,
|
|
1957
|
+
preview: {
|
|
1958
|
+
\u5173\u952E\u6210\u679C\u540D\u79F0: name,
|
|
1959
|
+
\u6240\u5C5E\u76EE\u6807: objectId,
|
|
1960
|
+
\u8D23\u4EFB\u4EBA: principalid,
|
|
1961
|
+
\u76EE\u6807\u503C: args.target_value ?? null,
|
|
1962
|
+
\u5B9E\u9645\u503C: args.actual_value ?? null,
|
|
1963
|
+
\u6743\u91CD: args.weight ?? null,
|
|
1964
|
+
\u8D77\u6B62\u65E5\u671F: range ? range.join(" ~ ") : null,
|
|
1965
|
+
\u64CD\u4F5C: krId ? `\u4FEE\u6539\uFF08${krId}\uFF09` : "\u65B0\u5EFA"
|
|
1966
|
+
},
|
|
1967
|
+
notes
|
|
1968
|
+
};
|
|
1969
|
+
}
|
|
1970
|
+
if (args.participants !== void 0) notes.push("standard_only_fields_ignored:participants");
|
|
1971
|
+
const mainTable = compact({
|
|
1972
|
+
...krId ? { id: krId } : {},
|
|
1973
|
+
object_id: toIdString(args.object_id, "object_id"),
|
|
1974
|
+
wk_name: name,
|
|
1975
|
+
principalid,
|
|
1976
|
+
...args.target_value === void 0 ? {} : { target_value: args.target_value },
|
|
1977
|
+
...args.actual_value === void 0 ? {} : { actual_value: args.actual_value },
|
|
1978
|
+
...args.weight === void 0 ? {} : { weight: args.weight },
|
|
1979
|
+
...args.progress === void 0 ? {} : { progress: args.progress },
|
|
1980
|
+
...args.score === void 0 ? {} : { score: args.score },
|
|
1981
|
+
...range ? { plan_start_end_0: range[0], plan_start_end_1: range[1] } : {},
|
|
1982
|
+
...args.kr_unit === void 0 ? {} : { kr_unit: String(args.kr_unit) },
|
|
1983
|
+
...args.confidence === void 0 ? {} : { confidence: args.confidence },
|
|
1984
|
+
...args.risk === void 0 ? {} : { risk: String(args.risk) }
|
|
1985
|
+
});
|
|
1986
|
+
return {
|
|
1987
|
+
link,
|
|
1988
|
+
endpoint: krId ? "eb-kr-update" : "eb-kr-create",
|
|
1989
|
+
body: mainTable,
|
|
1990
|
+
preview: {
|
|
1991
|
+
\u5173\u952E\u6210\u679C\u540D\u79F0: name,
|
|
1992
|
+
\u6240\u5C5E\u76EE\u6807: mainTable.object_id,
|
|
1993
|
+
\u8D23\u4EFB\u4EBA: principalid,
|
|
1994
|
+
\u76EE\u6807\u503C: args.target_value ?? null,
|
|
1995
|
+
\u5B9E\u9645\u503C: args.actual_value ?? null,
|
|
1996
|
+
\u6743\u91CD: args.weight ?? null,
|
|
1997
|
+
\u8D77\u6B62\u65E5\u671F: range ? range.join(" ~ ") : null,
|
|
1998
|
+
\u64CD\u4F5C: krId ? `\u4FEE\u6539\uFF08${krId}\uFF09` : "\u65B0\u5EFA"
|
|
1999
|
+
},
|
|
2000
|
+
notes
|
|
2001
|
+
};
|
|
2002
|
+
}
|
|
2003
|
+
var okrKrSavePrepare = {
|
|
2004
|
+
name: "okr.kr.save.prepare",
|
|
2005
|
+
resource: "okr",
|
|
2006
|
+
method: "kr.save.prepare",
|
|
2007
|
+
action: "okr.kr.save.prepare",
|
|
2008
|
+
summary: "\u51C6\u5907\u65B0\u5EFA/\u4FEE\u6539\u5173\u952E\u6210\u679C\uFF08\u4F20 kr_id \u4E3A\u4FEE\u6539\uFF0C\u4E0D\u4F20\u4E3A\u65B0\u5EFA\uFF09\uFF0C\u751F\u6210\u786E\u8BA4\u9884\u89C8\uFF0C\u4E0D\u5199\u5165",
|
|
2009
|
+
capability: "okr",
|
|
2010
|
+
risk: "read-before-write",
|
|
2011
|
+
requiresConfirmation: true,
|
|
2012
|
+
inputSchema: schemaOf({ ...KR_WRITE_FIELDS }, { required: ["object_id", "name"] }),
|
|
2013
|
+
handler: async (args, env) => {
|
|
2014
|
+
const payload = await buildKrPayload(args, env);
|
|
2015
|
+
const session = await env.host.getSession();
|
|
2016
|
+
const token = await env.continuation.issue(
|
|
2017
|
+
{
|
|
2018
|
+
operation: "okr.kr.save.apply",
|
|
2019
|
+
baseUrl: session.baseUrl,
|
|
2020
|
+
profile: session.profile,
|
|
2021
|
+
userId: session.userId,
|
|
2022
|
+
link: payload.link,
|
|
2023
|
+
endpoint: payload.endpoint,
|
|
2024
|
+
payload: payload.body,
|
|
2025
|
+
fingerprint: fingerprint(payload.body)
|
|
2026
|
+
},
|
|
2027
|
+
CONTINUATION_TTL_SECONDS * 1e3
|
|
2028
|
+
);
|
|
2029
|
+
return okrSuccess(
|
|
2030
|
+
"okr.kr.save.prepare",
|
|
2031
|
+
{
|
|
2032
|
+
status: "AWAITING_CONFIRMATION",
|
|
2033
|
+
link: payload.link,
|
|
2034
|
+
endpoint: payload.endpoint,
|
|
2035
|
+
preview: payload.preview,
|
|
2036
|
+
continuation: token,
|
|
2037
|
+
expiresInSeconds: CONTINUATION_TTL_SECONDS
|
|
2038
|
+
},
|
|
2039
|
+
payload.notes.length > 0 ? { notes: payload.notes } : void 0
|
|
2040
|
+
);
|
|
2041
|
+
}
|
|
2042
|
+
};
|
|
2043
|
+
var okrKrSaveApply = {
|
|
2044
|
+
name: "okr.kr.save.apply",
|
|
2045
|
+
resource: "okr",
|
|
2046
|
+
method: "kr.save.apply",
|
|
2047
|
+
action: "okr.kr.save.apply",
|
|
2048
|
+
summary: "\u63D0\u4EA4\u5173\u952E\u6210\u679C\u4FDD\u5B58\uFF1B\u5FC5\u987B\u5728\u7528\u6237\u660E\u786E\u786E\u8BA4\u540E\u8C03\u7528\uFF0C\u4E14\u8981\u6C42 prepare \u8FD4\u56DE\u7684 continuation",
|
|
2049
|
+
capability: "okr",
|
|
2050
|
+
risk: "high-risk-write",
|
|
2051
|
+
requiresConfirmation: true,
|
|
2052
|
+
inputSchema: schemaOf(
|
|
2053
|
+
{ ...KR_WRITE_FIELDS, confirm: { const: true }, continuation: { type: "string", minLength: 1 } },
|
|
2054
|
+
{ required: ["object_id", "name", "confirm", "continuation"] }
|
|
2055
|
+
),
|
|
2056
|
+
handler: async (args, env) => {
|
|
2057
|
+
const lease = await ensureConfirmLease(args, "okr.kr.save.apply", env);
|
|
2058
|
+
const body = lease.payload ?? {};
|
|
2059
|
+
if (lease.fingerprint !== fingerprint(body)) {
|
|
2060
|
+
throw okrValidationError("target_changed", "\u5199\u5165\u5185\u5BB9\u4E0E prepare \u65F6\u7684\u5FEB\u7167\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C prepare");
|
|
2061
|
+
}
|
|
2062
|
+
const session = await env.host.getSession();
|
|
2063
|
+
const endpoint = lease.endpoint;
|
|
2064
|
+
let response;
|
|
2065
|
+
try {
|
|
2066
|
+
if (endpoint === "standard-kr-save") {
|
|
2067
|
+
response = await env.host.request({
|
|
2068
|
+
method: "POST",
|
|
2069
|
+
path: "/api/workrelate/goal/fs/krForm/saveForm",
|
|
2070
|
+
operation: "okr.kr.save.apply",
|
|
2071
|
+
body
|
|
2072
|
+
});
|
|
2073
|
+
if (!isFlagSuccess(response)) {
|
|
2074
|
+
throw okrApiError("business_error", businessMessage(response), { response: businessMessage(response) });
|
|
2075
|
+
}
|
|
2076
|
+
} else {
|
|
2077
|
+
response = await env.host.request({
|
|
2078
|
+
method: "POST",
|
|
2079
|
+
path: endpoint === "eb-kr-create" ? "/api/ebuilder/form/formdata/v2/saveFormData/okr_createKeyResult" : "/api/ebuilder/form/formdata/v2/updateFormData/okr_updateKeyResult",
|
|
2080
|
+
operation: "okr.kr.save.apply",
|
|
2081
|
+
body: {
|
|
2082
|
+
datajson: {
|
|
2083
|
+
datas: [{ mainTable: body }],
|
|
2084
|
+
header: { operator: session.userId }
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
});
|
|
2088
|
+
if (!isDatajsonSuccess(response)) {
|
|
2089
|
+
throw okrApiError("business_error", businessMessage(response), { response: businessMessage(response) });
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
} catch (error) {
|
|
2093
|
+
if (error?.type === "network") {
|
|
2094
|
+
throw okrPartialError(
|
|
2095
|
+
"\u5173\u952E\u6210\u679C\u4FDD\u5B58\u8BF7\u6C42\u53D1\u9001\u540E\u8FDE\u63A5\u4E2D\u65AD\uFF0C\u662F\u5426\u5DF2\u5199\u5165\u4E0D\u786E\u5B9A\uFF0C\u7981\u6B62\u81EA\u52A8\u91CD\u8BD5\uFF0C\u8BF7\u901A\u8FC7 okr.get / okr.kr.list \u590D\u6838",
|
|
2096
|
+
{ attempted: { endpoint } },
|
|
2097
|
+
{ stage: endpoint }
|
|
2098
|
+
);
|
|
2099
|
+
}
|
|
2100
|
+
throw error;
|
|
2101
|
+
}
|
|
2102
|
+
return okrSuccess("okr.kr.save.apply", {
|
|
2103
|
+
status: "COMPLETE",
|
|
2104
|
+
link: lease.link,
|
|
2105
|
+
endpoint,
|
|
2106
|
+
result: response
|
|
2107
|
+
});
|
|
2108
|
+
}
|
|
2109
|
+
};
|
|
2110
|
+
var ALIGN_FIELDS = {
|
|
2111
|
+
current_id: { ...SCHEMA_ID, description: "\u5F53\u524D\u76EE\u6807 ID" },
|
|
2112
|
+
align_obj_id: { ...SCHEMA_ID, description: "\u5BF9\u9F50\u76EE\u6807 ID" },
|
|
2113
|
+
cur_obj_principalid: SCHEMA_PERSON_ID,
|
|
2114
|
+
ali_obj_principalid: SCHEMA_PERSON_ID
|
|
2115
|
+
};
|
|
2116
|
+
async function buildAlignPayload(args, env) {
|
|
2117
|
+
const { host } = env;
|
|
2118
|
+
const { link } = await resolveLink(host);
|
|
2119
|
+
assertLinkSupported(
|
|
2120
|
+
link,
|
|
2121
|
+
"eb",
|
|
2122
|
+
"okr.align.create",
|
|
2123
|
+
"e10 \u6807\u51C6\u7248\u94FE\u8DEF\u6E90\u8D44\u6599\u672A\u63D0\u4F9B\u300C\u6DFB\u52A0\u76EE\u6807\u5BF9\u9F50\u300D\u63A5\u53E3\uFF0C\u65E0\u6CD5\u6267\u884C\u76EE\u6807\u5BF9\u9F50"
|
|
2124
|
+
);
|
|
2125
|
+
const currentId = toIdString(args.current_id, "current_id");
|
|
2126
|
+
const alignObjId = toIdString(args.align_obj_id, "align_obj_id");
|
|
2127
|
+
if (currentId === alignObjId) {
|
|
2128
|
+
throw okrValidationError("align_invalid", "\u5F53\u524D\u76EE\u6807\u4E0E\u5BF9\u9F50\u76EE\u6807\u4E0D\u80FD\u662F\u540C\u4E00\u4E2A\u76EE\u6807");
|
|
2129
|
+
}
|
|
2130
|
+
let curPrincipal = args.cur_obj_principalid === void 0 ? null : toPersonIdString(args.cur_obj_principalid, "cur_obj_principalid");
|
|
2131
|
+
let aliPrincipal = args.ali_obj_principalid === void 0 ? null : toPersonIdString(args.ali_obj_principalid, "ali_obj_principalid");
|
|
2132
|
+
if (!curPrincipal) {
|
|
2133
|
+
const raw = await fetchGoalRaw(host, "eb", currentId);
|
|
2134
|
+
curPrincipal = goalPrincipalId(raw, "eb");
|
|
2135
|
+
}
|
|
2136
|
+
if (!aliPrincipal) {
|
|
2137
|
+
const raw = await fetchGoalRaw(host, "eb", alignObjId);
|
|
2138
|
+
aliPrincipal = goalPrincipalId(raw, "eb");
|
|
2139
|
+
}
|
|
2140
|
+
if (!curPrincipal || !aliPrincipal) {
|
|
2141
|
+
throw okrValidationError(
|
|
2142
|
+
"align_principal_unresolved",
|
|
2143
|
+
"\u65E0\u6CD5\u4ECE\u76EE\u6807\u8BE6\u60C5\u89E3\u6790\u53CC\u65B9\u8D1F\u8D23\u4EBA\uFF0C\u8BF7\u663E\u5F0F\u63D0\u4F9B cur_obj_principalid \u4E0E ali_obj_principalid\uFF08\u4EBA\u5458 ID \u7531 weaver-e10-hrm skill \u89E3\u6790\uFF09",
|
|
2144
|
+
{ currentId, alignObjId }
|
|
2145
|
+
);
|
|
2146
|
+
}
|
|
2147
|
+
const body = compact({
|
|
2148
|
+
current_id: currentId,
|
|
2149
|
+
align_obj_id: alignObjId,
|
|
2150
|
+
cur_obj_principalid: curPrincipal,
|
|
2151
|
+
ali_obj_principalid: aliPrincipal
|
|
2152
|
+
});
|
|
2153
|
+
return {
|
|
2154
|
+
body,
|
|
2155
|
+
preview: {
|
|
2156
|
+
\u5F53\u524D\u76EE\u6807: currentId,
|
|
2157
|
+
\u5F53\u524D\u76EE\u6807\u8D1F\u8D23\u4EBA: curPrincipal,
|
|
2158
|
+
\u5BF9\u9F50\u76EE\u6807: alignObjId,
|
|
2159
|
+
\u5BF9\u9F50\u76EE\u6807\u8D1F\u8D23\u4EBA: aliPrincipal
|
|
2160
|
+
}
|
|
2161
|
+
};
|
|
2162
|
+
}
|
|
2163
|
+
var okrAlignCreatePrepare = {
|
|
2164
|
+
name: "okr.align.create.prepare",
|
|
2165
|
+
resource: "okr",
|
|
2166
|
+
method: "align.create.prepare",
|
|
2167
|
+
action: "okr.align.create.prepare",
|
|
2168
|
+
summary: "\u51C6\u5907\u6DFB\u52A0\u76EE\u6807\u5BF9\u9F50\uFF08\u4EC5 ebuilder \u94FE\u8DEF\uFF09\uFF1A\u8865\u5168\u53CC\u65B9\u8D1F\u8D23\u4EBA\u5E76\u751F\u6210\u786E\u8BA4\u9884\u89C8\uFF0C\u4E0D\u5199\u5165",
|
|
2169
|
+
capability: "okr",
|
|
2170
|
+
risk: "read-before-write",
|
|
2171
|
+
requiresConfirmation: true,
|
|
2172
|
+
inputSchema: schemaOf({ ...ALIGN_FIELDS }, { required: ["current_id", "align_obj_id"] }),
|
|
2173
|
+
handler: async (args, env) => {
|
|
2174
|
+
const payload = await buildAlignPayload(args, env);
|
|
2175
|
+
const session = await env.host.getSession();
|
|
2176
|
+
const token = await env.continuation.issue(
|
|
2177
|
+
{
|
|
2178
|
+
operation: "okr.align.create.apply",
|
|
2179
|
+
baseUrl: session.baseUrl,
|
|
2180
|
+
profile: session.profile,
|
|
2181
|
+
userId: session.userId,
|
|
2182
|
+
link: "eb",
|
|
2183
|
+
payload: payload.body,
|
|
2184
|
+
fingerprint: fingerprint(payload.body)
|
|
2185
|
+
},
|
|
2186
|
+
CONTINUATION_TTL_SECONDS * 1e3
|
|
2187
|
+
);
|
|
2188
|
+
return okrSuccess("okr.align.create.prepare", {
|
|
2189
|
+
status: "AWAITING_CONFIRMATION",
|
|
2190
|
+
link: "eb",
|
|
2191
|
+
preview: payload.preview,
|
|
2192
|
+
continuation: token,
|
|
2193
|
+
expiresInSeconds: CONTINUATION_TTL_SECONDS
|
|
2194
|
+
});
|
|
2195
|
+
}
|
|
2196
|
+
};
|
|
2197
|
+
var okrAlignCreateApply = {
|
|
2198
|
+
name: "okr.align.create.apply",
|
|
2199
|
+
resource: "okr",
|
|
2200
|
+
method: "align.create.apply",
|
|
2201
|
+
action: "okr.align.create.apply",
|
|
2202
|
+
summary: "\u63D0\u4EA4\u6DFB\u52A0\u76EE\u6807\u5BF9\u9F50\uFF1B\u5FC5\u987B\u5728\u7528\u6237\u660E\u786E\u786E\u8BA4\u540E\u8C03\u7528\uFF0C\u4E14\u8981\u6C42 prepare \u8FD4\u56DE\u7684 continuation",
|
|
2203
|
+
capability: "okr",
|
|
2204
|
+
risk: "high-risk-write",
|
|
2205
|
+
requiresConfirmation: true,
|
|
2206
|
+
inputSchema: schemaOf(
|
|
2207
|
+
{ ...ALIGN_FIELDS, confirm: { const: true }, continuation: { type: "string", minLength: 1 } },
|
|
2208
|
+
{ required: ["current_id", "align_obj_id", "confirm", "continuation"] }
|
|
2209
|
+
),
|
|
2210
|
+
handler: async (args, env) => {
|
|
2211
|
+
const lease = await ensureConfirmLease(args, "okr.align.create.apply", env);
|
|
2212
|
+
const body = lease.payload ?? {};
|
|
2213
|
+
if (String(body.current_id ?? "") !== toIdString(args.current_id, "current_id")) {
|
|
2214
|
+
throw okrValidationError("target_changed", "\u5F53\u524D\u76EE\u6807 ID \u4E0E prepare \u65F6\u7684\u5FEB\u7167\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C prepare");
|
|
2215
|
+
}
|
|
2216
|
+
if (lease.fingerprint !== fingerprint(body)) {
|
|
2217
|
+
throw okrValidationError("target_changed", "\u5199\u5165\u5185\u5BB9\u4E0E prepare \u65F6\u7684\u5FEB\u7167\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C prepare");
|
|
2218
|
+
}
|
|
2219
|
+
const session = await env.host.getSession();
|
|
2220
|
+
let response;
|
|
2221
|
+
try {
|
|
2222
|
+
response = await env.host.request({
|
|
2223
|
+
method: "POST",
|
|
2224
|
+
path: "/api/ebuilder/form/formdata/v2/saveFormData/okr_createGoalAlign",
|
|
2225
|
+
operation: "okr.align.create.apply",
|
|
2226
|
+
body: {
|
|
2227
|
+
datajson: {
|
|
2228
|
+
datas: [{ mainTable: body }],
|
|
2229
|
+
header: { operator: session.userId }
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
});
|
|
2233
|
+
} catch (error) {
|
|
2234
|
+
if (error?.type === "network") {
|
|
2235
|
+
throw okrPartialError(
|
|
2236
|
+
"\u76EE\u6807\u5BF9\u9F50\u8BF7\u6C42\u53D1\u9001\u540E\u8FDE\u63A5\u4E2D\u65AD\uFF0C\u662F\u5426\u5DF2\u5199\u5165\u4E0D\u786E\u5B9A\uFF0C\u7981\u6B62\u81EA\u52A8\u91CD\u8BD5\uFF0C\u8BF7\u901A\u8FC7 okr.get \u590D\u6838",
|
|
2237
|
+
{ attempted: { current_id: body.current_id, align_obj_id: body.align_obj_id } },
|
|
2238
|
+
{ stage: "okr.align.create.apply" }
|
|
2239
|
+
);
|
|
2240
|
+
}
|
|
2241
|
+
throw error;
|
|
2242
|
+
}
|
|
2243
|
+
if (!isDatajsonSuccess(response)) {
|
|
2244
|
+
throw okrApiError("business_error", businessMessage(response), { response: businessMessage(response) });
|
|
2245
|
+
}
|
|
2246
|
+
return okrSuccess("okr.align.create.apply", {
|
|
2247
|
+
status: "COMPLETE",
|
|
2248
|
+
link: "eb",
|
|
2249
|
+
result: response
|
|
2250
|
+
});
|
|
2251
|
+
}
|
|
2252
|
+
};
|
|
2253
|
+
var okrWriteOperations = [
|
|
2254
|
+
...goalWriteDefinitions("create"),
|
|
2255
|
+
...goalWriteDefinitions("update"),
|
|
2256
|
+
okrKrSavePrepare,
|
|
2257
|
+
okrKrSaveApply,
|
|
2258
|
+
okrAlignCreatePrepare,
|
|
2259
|
+
okrAlignCreateApply
|
|
2260
|
+
];
|
|
2261
|
+
|
|
2262
|
+
// src/shortcuts/okr/operations/registry.ts
|
|
2263
|
+
function buildRegistry() {
|
|
2264
|
+
const registry = /* @__PURE__ */ new Map();
|
|
2265
|
+
const definitions = [
|
|
2266
|
+
...okrReadOperations,
|
|
2267
|
+
...okrWriteOperations
|
|
2268
|
+
];
|
|
2269
|
+
for (const definition of definitions) {
|
|
2270
|
+
if (registry.has(definition.name)) {
|
|
2271
|
+
throw new Error(`duplicate okr operation: ${definition.name}`);
|
|
2272
|
+
}
|
|
2273
|
+
registry.set(definition.name, definition);
|
|
2274
|
+
}
|
|
2275
|
+
return registry;
|
|
2276
|
+
}
|
|
2277
|
+
var okrOperationRegistry = buildRegistry();
|
|
2278
|
+
function okrOperationDefinitions() {
|
|
2279
|
+
return [...okrOperationRegistry.values()];
|
|
2280
|
+
}
|
|
2281
|
+
function getOkrOperation(operation) {
|
|
2282
|
+
const definition = okrOperationRegistry.get(operation);
|
|
2283
|
+
if (!definition) {
|
|
2284
|
+
throw okrValidationError("operation_unknown", `OKR \u76EE\u6807\u6A21\u5757\u4E0D\u652F\u6301\u64CD\u4F5C\uFF1A${operation}`);
|
|
2285
|
+
}
|
|
2286
|
+
return definition;
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
// src/shortcuts/okr/manifest.ts
|
|
2290
|
+
var WITHHELD = [
|
|
2291
|
+
{
|
|
2292
|
+
name: "okr.kr.list.standard",
|
|
2293
|
+
reason: "e10 \u6807\u51C6\u7248\u6E90\u8D44\u6599\u672A\u63D0\u4F9B\u72EC\u7ACB\u7684\u5173\u952E\u6210\u679C\u5206\u9875\u63A5\u53E3\uFF0C\u5173\u952E\u6210\u679C\u901A\u8FC7 okr.list \u7684 goals[].keyresultList \u6216 okr.get \u7684 goal.keyresultList \u83B7\u53D6\uFF1Bokr.kr.list \u4EC5\u652F\u6301 ebuilder \u94FE\u8DEF"
|
|
2294
|
+
},
|
|
2295
|
+
{
|
|
2296
|
+
name: "okr.comment.list.eb",
|
|
2297
|
+
reason: "ebuilder \u7248\u6E90\u8D44\u6599\u672A\u63D0\u4F9B\u76EE\u6807\u8BC4\u8BBA\u63A5\u53E3\uFF0Cokr.comment.list \u4EC5\u652F\u6301 e10 \u6807\u51C6\u7248\u94FE\u8DEF"
|
|
2298
|
+
},
|
|
2299
|
+
{
|
|
2300
|
+
name: "okr.align.create.standard",
|
|
2301
|
+
reason: "e10 \u6807\u51C6\u7248\u6E90\u8D44\u6599\u672A\u63D0\u4F9B\u300C\u6DFB\u52A0\u76EE\u6807\u5BF9\u9F50\u300D\u63A5\u53E3\uFF0Cokr.align.create.* \u4EC5\u652F\u6301 ebuilder \u94FE\u8DEF"
|
|
2302
|
+
},
|
|
2303
|
+
{
|
|
2304
|
+
name: "okr.eb.kr.delete",
|
|
2305
|
+
reason: "\u6E90\u8D44\u6599\u53EA\u63D0\u4F9B\u5173\u952E\u6210\u679C\u65B0\u5EFA\u4E0E\u7F16\u8F91\u63A5\u53E3\uFF0C\u6CA1\u6709\u5220\u9664\u5173\u952E\u6210\u679C\u63A5\u53E3\uFF0C\u6545\u4E0D\u751F\u6210\u5220\u9664 operation"
|
|
2306
|
+
}
|
|
2307
|
+
];
|
|
2308
|
+
function buildOperations() {
|
|
2309
|
+
return okrOperationDefinitions().map((definition) => ({
|
|
2310
|
+
name: definition.name,
|
|
2311
|
+
resource: definition.resource,
|
|
2312
|
+
summary: definition.summary,
|
|
2313
|
+
...definition.capability ? { capability: definition.capability } : {},
|
|
2314
|
+
risk: definition.risk,
|
|
2315
|
+
...definition.requiresConfirmation ? { requiresConfirmation: true } : {},
|
|
2316
|
+
inputSchema: definition.inputSchema
|
|
2317
|
+
}));
|
|
2318
|
+
}
|
|
2319
|
+
var okrManifest = {
|
|
2320
|
+
schemaVersion: 1,
|
|
2321
|
+
name: "okr",
|
|
2322
|
+
title: "\u6CDB\u5FAEE10 OKR \u76EE\u6807\u7BA1\u7406\uFF08\u76EE\u6807\u67E5\u8BE2/\u65B0\u5EFA/\u7F16\u8F91\u3001\u5173\u952E\u6210\u679C\u3001\u76EE\u6807\u5BF9\u9F50\u3001\u8BC4\u8BBA\uFF09",
|
|
2323
|
+
version: "0.1.0",
|
|
2324
|
+
host: "e10-okr",
|
|
2325
|
+
status: "builtin",
|
|
2326
|
+
sourceSkill: "weaver-e10-okr",
|
|
2327
|
+
capabilities: ["okr"],
|
|
2328
|
+
/**
|
|
2329
|
+
* OKR 目标接口链路路由:先读租户隔离、有效期 1 天的版本判定缓存,未命中才调用 okr_searchAppver
|
|
2330
|
+
* 读取 ver_name;`ver_name >= V2` 走 e10-ebuilder 链路,其它情况走 e10 标准版链路。
|
|
2331
|
+
* ebuilder 链路命中后严禁混用标准版接口,反之亦然。
|
|
2332
|
+
*/
|
|
2333
|
+
linkRouting: {
|
|
2334
|
+
versionInterface: "okr_searchAppver",
|
|
2335
|
+
versionField: "ver_name",
|
|
2336
|
+
ebWhen: ">=V2",
|
|
2337
|
+
cacheKeyPrefix: "okr:version:",
|
|
2338
|
+
cacheTtlSeconds: 86400,
|
|
2339
|
+
ebAppTag: "weaver-wr-goal-eb",
|
|
2340
|
+
ebFormTag: "uf_wrgm_baseinfo",
|
|
2341
|
+
ebFormIdFixedTenants: { tqasclatif: "1027322801024458753" },
|
|
2342
|
+
ebFormIdCache: "permanent-per-tenant",
|
|
2343
|
+
standardDetailUrl: "/sp/goal/openDetail?id={goalId}",
|
|
2344
|
+
ebDetailUrl: "/sp/ebdfpage/card/0/{okr\u76EE\u6807\u8BE6\u60C5eb\u8868\u5355id}/{goalId}"
|
|
2345
|
+
},
|
|
2346
|
+
/** 源资料强制规则:分页目标列表固定列,目标名称可点击跳转详情。 */
|
|
2347
|
+
goalTableColumns: ["\u76EE\u6807\u540D\u79F0", "\u76EE\u6807\u8D23\u4EFB\u4EBA\u540D\u79F0", "\u76EE\u6807\u5468\u671F\u7C7B\u578B", "\u76EE\u6807\u5468\u671F\u8303\u56F4"],
|
|
2348
|
+
/** 源资料强制规则:人员 ID 必须先由 weaver-e10-hrm skill 解析,禁止直接传人员名称,禁止取 userId 字段。 */
|
|
2349
|
+
personIdSource: "weaver-e10-hrm",
|
|
2350
|
+
operations: buildOperations(),
|
|
2351
|
+
withheldOperations: WITHHELD
|
|
2352
|
+
};
|
|
2353
|
+
|
|
2354
|
+
// src/shortcuts/okr/operations.ts
|
|
2355
|
+
async function executeOkrOperation(operation, rawInput, context) {
|
|
2356
|
+
const definition = getOkrOperation(operation);
|
|
2357
|
+
const input = asObject(rawInput);
|
|
2358
|
+
assertNoForbiddenKeys(input);
|
|
2359
|
+
return definition.handler(input, context);
|
|
2360
|
+
}
|
|
2361
|
+
|
|
2362
|
+
// src/shortcuts/okr/index.ts
|
|
2363
|
+
function asOptions(value) {
|
|
2364
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
2365
|
+
}
|
|
2366
|
+
async function readStdin() {
|
|
2367
|
+
const chunks = [];
|
|
2368
|
+
for await (const chunk of process.stdin) {
|
|
2369
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
2370
|
+
}
|
|
2371
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
2372
|
+
}
|
|
2373
|
+
function stripBom(value) {
|
|
2374
|
+
return value.replace(/^\uFEFF+/, "");
|
|
2375
|
+
}
|
|
2376
|
+
async function inputFrom(options, extra = {}) {
|
|
2377
|
+
const opts = asOptions(options);
|
|
2378
|
+
let input = {};
|
|
2379
|
+
if (opts.input && opts.inputJson) {
|
|
2380
|
+
throw okrValidationError("input_conflict", "\u4E0D\u80FD\u540C\u65F6\u4F20 --input \u548C --input-json");
|
|
2381
|
+
}
|
|
2382
|
+
if (opts.inputJson) {
|
|
2383
|
+
input = parseJsonInput(String(opts.inputJson), "--input-json");
|
|
2384
|
+
}
|
|
2385
|
+
if (opts.input) {
|
|
2386
|
+
let raw;
|
|
2387
|
+
try {
|
|
2388
|
+
raw = stripBom(opts.input === "-" ? await readStdin() : await readFile3(String(opts.input), "utf8"));
|
|
2389
|
+
} catch {
|
|
2390
|
+
throw okrValidationError("input_unreadable", `\u65E0\u6CD5\u8BFB\u53D6 --input\uFF1A${String(opts.input)}`);
|
|
2391
|
+
}
|
|
2392
|
+
input = parseJsonInput(raw, "--input");
|
|
2393
|
+
}
|
|
2394
|
+
return {
|
|
2395
|
+
...input,
|
|
2396
|
+
...Object.fromEntries(Object.entries(extra).filter(([, value]) => value !== void 0 && value !== ""))
|
|
2397
|
+
};
|
|
2398
|
+
}
|
|
2399
|
+
function parseJsonInput(raw, label) {
|
|
2400
|
+
try {
|
|
2401
|
+
const parsed = JSON.parse(stripBom(raw));
|
|
2402
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2403
|
+
throw new Error("input must be an object");
|
|
2404
|
+
}
|
|
2405
|
+
return parsed;
|
|
2406
|
+
} catch {
|
|
2407
|
+
throw okrValidationError("input_invalid", `${label} \u4E0D\u662F\u5408\u6CD5 JSON \u5BF9\u8C61`);
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
function successEnvelope(operation, result) {
|
|
2411
|
+
return {
|
|
2412
|
+
schemaVersion: 1,
|
|
2413
|
+
ok: true,
|
|
2414
|
+
operation,
|
|
2415
|
+
data: result.data === void 0 ? null : result.data,
|
|
2416
|
+
...result.meta ? { meta: result.meta } : {},
|
|
2417
|
+
warnings: []
|
|
2418
|
+
};
|
|
2419
|
+
}
|
|
2420
|
+
function failureEnvelope(error) {
|
|
2421
|
+
const structured = error;
|
|
2422
|
+
return {
|
|
2423
|
+
schemaVersion: 1,
|
|
2424
|
+
ok: false,
|
|
2425
|
+
...structured?.partialData === void 0 ? {} : { data: structured.partialData },
|
|
2426
|
+
error: toErrorEnvelope(error)
|
|
2427
|
+
};
|
|
2428
|
+
}
|
|
2429
|
+
async function executeAndPrint(ctx, operation, input) {
|
|
2430
|
+
try {
|
|
2431
|
+
const result = await executeOkrOperation(operation, input, {
|
|
2432
|
+
ctx,
|
|
2433
|
+
host: createOkrHost(ctx),
|
|
2434
|
+
continuation: createOkrContinuationSigner(ctx)
|
|
2435
|
+
});
|
|
2436
|
+
ctx.output.write(successEnvelope(operation, result), { json: true });
|
|
2437
|
+
} catch (error) {
|
|
2438
|
+
console.error(JSON.stringify(failureEnvelope(error), null, 2));
|
|
2439
|
+
process.exitCode = isCliError(error) ? error.exitCode : 1 /* GeneralError */;
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2442
|
+
var okrShortcut = {
|
|
2443
|
+
name: "okr",
|
|
2444
|
+
description: "\u6CDB\u5FAEE10 OKR \u76EE\u6807\u7BA1\u7406 CLI\uFF08\u76EE\u6807\u67E5\u8BE2/\u65B0\u5EFA/\u7F16\u8F91\u3001\u5173\u952E\u6210\u679C\u3001\u76EE\u6807\u5BF9\u9F50\u3001\u8BC4\u8BBA\uFF09",
|
|
2445
|
+
category: "shortcut",
|
|
2446
|
+
register({ program, action }) {
|
|
2447
|
+
const okr = program.command("okr").description("\u6CDB\u5FAEE10 OKR \u76EE\u6807\u7BA1\u7406\uFF08\u76EE\u6807\u5217\u8868/\u8BE6\u60C5/\u65B0\u5EFA/\u7F16\u8F91\u3001\u5173\u952E\u6210\u679C\u3001\u76EE\u6807\u5BF9\u9F50\u3001\u8BC4\u8BBA\u3001\u94FE\u8DEF\u5224\u5B9A\uFF09");
|
|
2448
|
+
okr.command("schema").description("Print okr operation manifest for agents").action(action((ctx) => {
|
|
2449
|
+
ctx.output.write(okrManifest, { json: true });
|
|
2450
|
+
}));
|
|
2451
|
+
okr.command("run").description("Run an okr operation with JSON input").argument("<operation>", "operation name, e.g. okr.list").option("--input <path>", "JSON input file, or - for stdin").option("--input-json <json>", "inline JSON input object").action(action(async (ctx, operation, options) => {
|
|
2452
|
+
await executeAndPrint(ctx, String(operation), await inputFrom(options));
|
|
2453
|
+
}));
|
|
2454
|
+
okr.command("route").description("\u5224\u5B9A\u5F53\u524D\u79DF\u6237 OKR \u63A5\u53E3\u94FE\u8DEF\uFF08okr.version.check \u8584\u5305\u88C5\uFF09").option("--refresh", "\u5FFD\u7565 1 \u5929\u79DF\u6237\u7F13\u5B58\uFF0C\u5F3A\u5236\u91CD\u65B0\u5224\u5B9A").action(action(async (ctx, options) => {
|
|
2455
|
+
const opts = asOptions(options);
|
|
2456
|
+
await executeAndPrint(ctx, "okr.version.check", opts.refresh ? { refresh: true } : {});
|
|
2457
|
+
}));
|
|
2458
|
+
okr.command("get").description("\u67E5\u8BE2\u5355\u4E2A\u76EE\u6807\u8BE6\u60C5\uFF08okr.get \u8584\u5305\u88C5\uFF09").option("--input <path>", "JSON input file, or - for stdin").option("--input-json <json>", "inline JSON input object").option("--id <id>", "\u76EE\u6807 ID").action(action(async (ctx, options) => {
|
|
2459
|
+
const opts = asOptions(options);
|
|
2460
|
+
await executeAndPrint(ctx, "okr.get", await inputFrom(options, { id: opts.id }));
|
|
2461
|
+
}));
|
|
2462
|
+
okr.command("list").description("\u5206\u9875\u67E5\u8BE2\u76EE\u6807\u5217\u8868\uFF08okr.list \u8584\u5305\u88C5\uFF09").option("--input <path>", "JSON input file, or - for stdin").option("--input-json <json>", "inline JSON input object").option("--period-type <type>", "\u5468\u671F\u7C7B\u578B\uFF1A1-\u5E74\u5EA6 2-\u5B63\u5EA6 3-\u6708\u5EA6 4-\u81EA\u5B9A\u4E49").option("--period-range <range>", "\u5468\u671F\u8303\u56F4\uFF1A\u5E74\u5EA6/\u5B63\u5EA6\u4E3A yyyy\uFF0C\u6708\u5EA6\u4E3A yyyy-MM\uFF0C\u81EA\u5B9A\u4E49\u4E3A\u300C\u5F00\u59CB\u65E5\u671F,\u7ED3\u675F\u65E5\u671F\u300D").option("--period-quarter <quarter>", "\u5B63\u5EA6\u503C 1-4").option("--page-no <n>", "\u9875\u7801").option("--page-size <n>", "\u6BCF\u9875\u6761\u6570").action(action(async (ctx, options) => {
|
|
2463
|
+
const opts = asOptions(options);
|
|
2464
|
+
await executeAndPrint(ctx, "okr.list", await inputFrom(options, {
|
|
2465
|
+
period_type: opts.periodType,
|
|
2466
|
+
period_range: opts.periodRange,
|
|
2467
|
+
period_quarter: opts.periodQuarter,
|
|
2468
|
+
page_no: opts.pageNo,
|
|
2469
|
+
page_size: opts.pageSize
|
|
2470
|
+
}));
|
|
2471
|
+
}));
|
|
2472
|
+
okr.command("viewlink").description("\u4E3A\u5DF2\u6709\u76EE\u6807 ID \u751F\u6210\u8BE6\u60C5\u9875\u94FE\u63A5\uFF08okr.viewlink \u8584\u5305\u88C5\uFF09").option("--input <path>", "JSON input file, or - for stdin").option("--input-json <json>", "inline JSON input object").option("--ids <ids>", "\u76EE\u6807 ID\uFF0C\u82F1\u6587\u9017\u53F7\u62FC\u63A5").action(action(async (ctx, options) => {
|
|
2473
|
+
const opts = asOptions(options);
|
|
2474
|
+
await executeAndPrint(ctx, "okr.viewlink", await inputFrom(options, { ids: opts.ids }));
|
|
2475
|
+
}));
|
|
2476
|
+
}
|
|
2477
|
+
};
|
|
2478
|
+
export {
|
|
2479
|
+
inputFrom,
|
|
2480
|
+
okrShortcut,
|
|
2481
|
+
successEnvelope
|
|
2482
|
+
};
|