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.
Files changed (219) hide show
  1. package/dist/chunks/archive-U766FTFH.js +2537 -0
  2. package/dist/chunks/archive-oa-DMWEKX3L.js +1317 -0
  3. package/dist/chunks/asset-TCR7VDEV.js +2109 -0
  4. package/dist/chunks/attachment-content-AQNX5N3S.js +23 -0
  5. package/dist/chunks/blog-EVZWGDVM.js +2157 -0
  6. package/dist/chunks/caizhilian-JOWS6SL5.js +10087 -0
  7. package/dist/chunks/calendar-5WNCV66Q.js +1195 -0
  8. package/dist/chunks/chunk-2DUV44UX.js +15606 -0
  9. package/dist/chunks/chunk-324YPTC2.js +1607 -0
  10. package/dist/chunks/chunk-65QMVWHS.js +231 -0
  11. package/dist/chunks/chunk-6V7ZLF34.js +387 -0
  12. package/dist/chunks/chunk-AC7KJWC5.js +358 -0
  13. package/dist/chunks/chunk-AJ62BGAW.js +29 -0
  14. package/dist/chunks/chunk-BUSC6UAE.js +43 -0
  15. package/dist/chunks/chunk-CVZ2JOSW.js +62 -0
  16. package/dist/chunks/chunk-D4LTJSJD.js +477 -0
  17. package/dist/chunks/chunk-EG6ZU444.js +654 -0
  18. package/dist/chunks/chunk-EZALDOQH.js +383 -0
  19. package/dist/chunks/chunk-FMPJJYYI.js +106 -0
  20. package/dist/chunks/chunk-G2JSIUWF.js +769 -0
  21. package/dist/chunks/chunk-GCG2NMWR.js +703 -0
  22. package/dist/chunks/chunk-GPMFD4RD.js +75 -0
  23. package/dist/chunks/chunk-H3WDBYJW.js +508 -0
  24. package/dist/chunks/chunk-H6XSTSLM.js +2357 -0
  25. package/dist/chunks/chunk-J7RJTZSV.js +5556 -0
  26. package/dist/chunks/chunk-LUSPKZKY.js +53 -0
  27. package/dist/chunks/chunk-NIAJ5ZCG.js +73 -0
  28. package/dist/chunks/chunk-NOODWMCL.js +584 -0
  29. package/dist/chunks/chunk-OOUTBLZ4.js +51 -0
  30. package/dist/chunks/chunk-P26ZWSKU.js +73 -0
  31. package/dist/chunks/chunk-QWY6PGL6.js +3472 -0
  32. package/dist/chunks/chunk-R2IJAK7T.js +464 -0
  33. package/dist/chunks/chunk-R7O5PUWO.js +205 -0
  34. package/dist/chunks/chunk-RCGYCOMG.js +6962 -0
  35. package/dist/chunks/chunk-VZTXRG6X.js +403 -0
  36. package/dist/chunks/chunk-WHD4XMRP.js +161 -0
  37. package/dist/chunks/chunk-YLCYX7LE.js +371 -0
  38. package/dist/chunks/chunk-ZEDWSH32.js +68 -0
  39. package/dist/chunks/continuation-2CKSBLA6.js +11 -0
  40. package/dist/chunks/continuation-HZIZRZBX.js +13 -0
  41. package/dist/chunks/continuation-NLECEJPX.js +11 -0
  42. package/dist/chunks/ebuilder-form-NJ4YK6CC.js +2276 -0
  43. package/dist/chunks/ehr-MMYN36VA.js +5241 -0
  44. package/dist/chunks/employee-SAK2QYXX.js +11 -0
  45. package/dist/chunks/esb-HIWHOU7Q.js +141 -0
  46. package/dist/chunks/fna-KBACQTA5.js +1444 -0
  47. package/dist/chunks/host-3OHS5QUX.js +21 -0
  48. package/dist/chunks/host-IG6KEH5Q.js +19 -0
  49. package/dist/chunks/host-KQL5N4HO.js +23 -0
  50. package/dist/chunks/host-LLSZQCWR.js +17 -0
  51. package/dist/chunks/hrm-LYEC67ZQ.js +244 -0
  52. package/dist/chunks/im-RN2UKAEU.js +252 -0
  53. package/dist/chunks/invoice-EEPHLAF6.js +5179 -0
  54. package/dist/chunks/jiuchuanhui-WVVZYSJE.js +1940 -0
  55. package/dist/chunks/lazy-dispatch-MDOFFL2S.js +28 -0
  56. package/dist/chunks/mail-LNQLTF6L.js +2695 -0
  57. package/dist/chunks/meeting-XSD3BDVQ.js +504 -0
  58. package/dist/chunks/msg-parse-4GSQ2WTO.js +41 -0
  59. package/dist/chunks/okr-TMWTIU2K.js +2482 -0
  60. package/dist/chunks/plan-A2FSFA7T.js +2025 -0
  61. package/dist/chunks/project-T26QLBQF.js +1361 -0
  62. package/dist/chunks/registry-2VLUAESA.js +14 -0
  63. package/dist/chunks/registry-JCFEYXOE.js +18 -0
  64. package/dist/chunks/registry-NYPYMZXG.js +16 -0
  65. package/dist/chunks/registry-Q7OQJ3SU.js +19 -0
  66. package/dist/chunks/registry-ZJMJVWFA.js +19 -0
  67. package/dist/chunks/room-recommend-UR4ZDZS6.js +20 -0
  68. package/dist/chunks/schedule-5L2PM4M6.js +24 -0
  69. package/dist/chunks/state-Y2XBP6YE.js +15 -0
  70. package/dist/chunks/workflow-TR6PG2SL.js +245 -0
  71. package/dist/cmd/argv.js +45 -0
  72. package/dist/cmd/docs/index.js +3 -3
  73. package/dist/cmd/lazy-dispatch.js +20 -0
  74. package/dist/cmd/root.js +2 -4
  75. package/dist/cmd/setup/index.js +2 -2
  76. package/dist/cmd/skills/index.js +2 -2
  77. package/dist/core/package-paths.js +47 -0
  78. package/dist/index.js +163 -7
  79. package/dist/internal/e10/auth/xiaoe.js +3 -3
  80. package/dist/internal/e10/request-runtime.js +18 -62
  81. package/dist/internal/skills/detector.js +2 -2
  82. package/dist/shortcuts/contract/data/performance-catalog.js +1306 -0
  83. package/dist/shortcuts/contract/host.js +91 -35
  84. package/dist/shortcuts/contract/index.js +213 -0
  85. package/dist/shortcuts/contract/manifest.js +928 -0
  86. package/dist/shortcuts/contract/ooxml/docx.js +295 -0
  87. package/dist/shortcuts/contract/ooxml/xlsx.js +221 -0
  88. package/dist/shortcuts/contract/ooxml/zip.js +158 -0
  89. package/dist/shortcuts/contract/operations/assistant.js +1156 -0
  90. package/dist/shortcuts/contract/operations/clause-library.js +522 -0
  91. package/dist/shortcuts/contract/operations/compare.js +193 -0
  92. package/dist/shortcuts/contract/operations/credit-page.js +34 -0
  93. package/dist/shortcuts/contract/operations/flow.js +98 -0
  94. package/dist/shortcuts/contract/operations/page.js +66 -0
  95. package/dist/shortcuts/contract/operations/performance.js +733 -0
  96. package/dist/shortcuts/contract/operations/quote.js +557 -0
  97. package/dist/shortcuts/contract/operations/recommend.js +78 -0
  98. package/dist/shortcuts/contract/operations/registry.js +18 -0
  99. package/dist/shortcuts/contract/operations/review.js +83 -0
  100. package/dist/shortcuts/contract/operations/shared.js +37 -0
  101. package/dist/shortcuts/contract/operations/upload.js +108 -0
  102. package/dist/shortcuts/contract/operations/write.js +3 -2
  103. package/dist/shortcuts/index.js +140 -40
  104. package/dist/shortcuts/invoice/host.js +2 -1
  105. package/dist/shortcuts/invoice/manifest.js +36 -12
  106. package/dist/shortcuts/invoice/operations/issuing-qys.js +132 -36
  107. package/dist/shortcuts/invoice/operations/reim-auto.js +9 -0
  108. package/dist/shortcuts/invoice/operations/reim.js +81 -5
  109. package/dist/shortcuts/invoice/operations/shared.js +12 -5
  110. package/dist/shortcuts/meeting/host.js +45 -3
  111. package/dist/shortcuts/meeting/invitation/docx.js +442 -0
  112. package/dist/shortcuts/meeting/operations/attachment-content.js +418 -0
  113. package/dist/shortcuts/meeting/operations/attachment.js +442 -0
  114. package/dist/shortcuts/meeting/operations/eb/cache.js +57 -0
  115. package/dist/shortcuts/meeting/operations/eb/catalog.js +343 -28
  116. package/dist/shortcuts/meeting/operations/eb/conflict.js +372 -11
  117. package/dist/shortcuts/meeting/operations/eb/create-flow.js +710 -0
  118. package/dist/shortcuts/meeting/operations/eb/decision.js +47 -1
  119. package/dist/shortcuts/meeting/operations/eb/factory.js +129 -11
  120. package/dist/shortcuts/meeting/operations/eb/index.js +122 -2
  121. package/dist/shortcuts/meeting/operations/eb/room-recommend.js +378 -0
  122. package/dist/shortcuts/meeting/operations/eb/room-summary.js +84 -0
  123. package/dist/shortcuts/meeting/operations/eb/schedule.js +450 -0
  124. package/dist/shortcuts/meeting/operations/from-group-chat.js +576 -0
  125. package/dist/shortcuts/meeting/operations/invitation.js +458 -0
  126. package/dist/shortcuts/meeting/operations/minute-content.js +266 -0
  127. package/dist/shortcuts/meeting/operations/pipeline.js +489 -0
  128. package/dist/shortcuts/meeting/operations/qrcode.js +131 -0
  129. package/dist/shortcuts/meeting/operations/receipts.js +1 -1
  130. package/dist/shortcuts/meeting/operations/registry.js +18 -0
  131. package/dist/shortcuts/meeting/operations/summary.js +276 -0
  132. package/dist/shortcuts/meeting/operations/task-notify.js +325 -0
  133. package/dist/shortcuts/meeting/operations.js +42 -1
  134. package/dist/shortcuts/meeting/qr/encoder.js +427 -0
  135. package/dist/shortcuts/meeting/qr/render.js +103 -0
  136. package/dist/shortcuts/workflow/index.js +3 -0
  137. package/dist/shortcuts/workflow/operations/form.js +17 -5
  138. package/dist/shortcuts/workflow/operations/read.js +13 -6
  139. package/dist/shortcuts/workflow/operations/registry.js +2 -0
  140. package/dist/shortcuts/workflow/operations/todoSmartConvert/businessRules.js +331 -0
  141. package/dist/shortcuts/workflow/operations/todoSmartConvert/detailFieldRules.js +133 -0
  142. package/dist/shortcuts/workflow/operations/todoSmartConvert/summaryCache.js +326 -0
  143. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailCache.js +113 -0
  144. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailFetcher.js +259 -0
  145. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoListRows.js +64 -0
  146. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoOutputPlanner.js +28 -0
  147. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.aggregate.js +70 -0
  148. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +267 -0
  149. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +392 -0
  150. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.detail.js +165 -0
  151. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +448 -0
  152. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +348 -0
  153. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +222 -0
  154. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.pipeline.js +66 -0
  155. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +502 -0
  156. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +540 -0
  157. package/docs/_catalog.md +1 -0
  158. package/docs/contract.md +39 -4
  159. package/docs/invoice.md +7 -7
  160. package/docs/todo-smart-convert/README.md +171 -0
  161. package/docs/todo-smart-convert/data-contract.md +236 -0
  162. package/docs/todo-smart-convert/mock/ai-todo-query-target.json +209 -0
  163. package/docs/todo-smart-convert/subgroup-rules.md +245 -0
  164. package/package.json +3 -2
  165. package/scripts/bundle.mjs +63 -0
  166. package/scripts/package-skill.mjs +1 -1
  167. package/skill-template/business-info.json +25 -4
  168. package/skill-template/domains/jinchengda.md +16 -3
  169. package/skill-template/domains/yepiaotong.md +3 -3
  170. package/skills/weaver-e10-jinchengda/SKILL.md +111 -31
  171. package/skills/weaver-e10-jinchengda/references/contract-agent-entry.md +7 -13
  172. package/skills/weaver-e10-jinchengda/references/contract-ai-assistant.md +150 -0
  173. package/skills/weaver-e10-jinchengda/references/contract-ai-review.md +87 -0
  174. package/skills/weaver-e10-jinchengda/references/contract-clause-library-crud.md +111 -0
  175. package/skills/weaver-e10-jinchengda/references/contract-clause-recommender.md +0 -15
  176. package/skills/weaver-e10-jinchengda/references/contract-clause-reference-save.md +0 -13
  177. package/skills/weaver-e10-jinchengda/references/contract-credit-page.md +50 -0
  178. package/skills/weaver-e10-jinchengda/references/contract-disabled-capabilities.md +4 -2
  179. package/skills/weaver-e10-jinchengda/references/contract-doc-compare.md +74 -0
  180. package/skills/weaver-e10-jinchengda/references/contract-flow-launch.md +84 -0
  181. package/skills/weaver-e10-jinchengda/references/contract-performance-query.md +29 -0
  182. package/skills/weaver-e10-jinchengda/references/contract-quote-to-contract.md +28 -0
  183. package/skills/weaver-e10-jinchengda/references/contract-request-status.md +2 -21
  184. package/skills/weaver-e10-jinchengda/references/contract-request-write.md +0 -24
  185. package/skills/weaver-e10-jinchengda/references/contract-signing-subjects.md +0 -15
  186. package/skills/weaver-e10-jinchengda/references/contract-subject-create.md +0 -17
  187. package/skills/weaver-e10-jinchengda/references/contract-template-recommend.md +70 -0
  188. package/skills/weaver-e10-jinchengda/references/contract-template-selector.md +0 -15
  189. package/skills/weaver-e10-jinchengda/references/contract-workflow-discovery.md +0 -15
  190. package/skills/weaver-e10-jinchengda/references/source-manifest.json +1168 -152
  191. package/skills/weaver-e10-meeting/SKILL.md +493 -17
  192. package/skills/weaver-e10-meeting/references/meeting-change.md +4 -4
  193. package/skills/weaver-e10-meeting/references/meeting-create.md +6 -6
  194. package/skills/weaver-e10-meeting/references/meeting-eb.md +503 -27
  195. package/skills/weaver-e10-meeting/references/meeting-invitation.md +113 -0
  196. package/skills/weaver-e10-meeting/references/meeting-lifecycle.md +6 -6
  197. package/skills/weaver-e10-meeting/references/meeting-minute-file.md +425 -0
  198. package/skills/weaver-e10-meeting/references/meeting-queries.md +4 -4
  199. package/skills/weaver-e10-meeting/references/meeting-receipts-signs.md +15 -15
  200. package/skills/weaver-e10-meeting/references/meeting-verification.md +19 -11
  201. package/skills/weaver-e10-meeting.zip +0 -0
  202. package/skills/weaver-e10-workflow/SKILL.md +23 -1
  203. package/skills/weaver-e10-workflow/references/todo-smart-convert.md +282 -0
  204. package/skills/weaver-e10-workflow/scripts/todo-summary.cjs +695 -0
  205. package/skills/weaver-e10-yepiaotong/SKILL.md +15 -11
  206. package/skills/weaver-e10-yepiaotong/references/invoice-enterprise-list.md +1 -1
  207. package/skills/weaver-e10-yepiaotong/references/invoice-issuing-examples.md +10 -7
  208. package/skills/weaver-e10-yepiaotong/references/invoice-issuing-form-fill-rules.md +41 -14
  209. package/skills/weaver-e10-yepiaotong/references/invoice-issuing-workflow.md +54 -26
  210. package/skills/weaver-e10-yepiaotong/references/invoice-personal-list.md +6 -5
  211. package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +14 -11
  212. package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +97 -56
  213. package/skills/weaver-e10-yepiaotong/references/reim-examples.md +84 -60
  214. package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +142 -105
  215. package/skills/weaver-e10-yepiaotong/references/reim-matching-rules.md +53 -194
  216. package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +7 -7
  217. package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +164 -72
  218. package/skills/weaver-e10-yepiaotong/references/source-manifest.json +8 -2
  219. package/templates/meeting/invitation.docx +0 -0
@@ -0,0 +1,522 @@
1
+ import { ContractCliError, contractPolicyError, contractValidationError } from '../errors.js';
2
+ import { clauseLibraryPageUrl } from './page.js';
3
+ import { ContractReadOperation } from './read.js';
4
+ import { bodyFrom, fingerprintFields, requireId, requireNonEmptyString } from './shared.js';
5
+ import { ContractWriteApplyOperation, ContractWritePrepareOperation } from './write.js';
6
+ const PERMISSION_PATH = '/api/ebd/contract/component/checkPermissionV2';
7
+ const TREE_BASE = '/api/ebd/contract/tree';
8
+ const INFO_BASE = '/api/ebd/contract/clauseinfo';
9
+ const GROUP_BASE = '/api/ebd/contract/clausegroup';
10
+ /** 条款库鉴权固定业务头,来源见 clause-library.md「权限鉴权」。 */
11
+ const CLAUSE_HEADERS = { ebbusinessid: '10000000000000000' };
12
+ /**
13
+ * 条款库 CRUD 前的强制鉴权门。
14
+ * 放行依据只有 data.checkPermission === true;hasLicense / privateDeploy / isRelease 不作为放行依据。
15
+ */
16
+ export async function assertClausePermission(host) {
17
+ const value = await host.contractRequest({
18
+ method: 'GET',
19
+ path: PERMISSION_PATH,
20
+ query: { moduleFlag: 'termComponent' },
21
+ headers: CLAUSE_HEADERS,
22
+ });
23
+ const data = (value?.data ?? {});
24
+ const denied = value?.status === false || value?.fail === true || data.checkPermission !== true;
25
+ if (denied) {
26
+ throw contractPolicyError('clause_no_permission', '暂无权限访问条款库(checkPermissionV2 未返回 data.checkPermission=true);已中止后续所有条款库接口,不要重试或换接口绕行', { path: PERMISSION_PATH, status: value?.status, fail: value?.fail, hasLicense: data.hasLicense });
27
+ }
28
+ return {
29
+ checkPermission: true,
30
+ hasLicense: data.hasLicense,
31
+ privateDeploy: data.privateDeploy,
32
+ dataInfo: data.dataInfo,
33
+ };
34
+ }
35
+ /** 所有条款库 operation 统一在入口处鉴权,包括查询类。 */
36
+ class ClauseGatedOperation {
37
+ name;
38
+ inner;
39
+ constructor(name, inner) {
40
+ this.name = name;
41
+ this.inner = inner;
42
+ }
43
+ async execute(input, context) {
44
+ await assertClausePermission(context.host);
45
+ return this.inner.execute(input, context);
46
+ }
47
+ }
48
+ /** 从分页接口的多种返回形状里取记录数组。 */
49
+ function recordsOf(value) {
50
+ const data = value?.data ?? {};
51
+ for (const candidate of [data.records, data.list, data.rows, data.data, data]) {
52
+ if (Array.isArray(candidate))
53
+ return candidate;
54
+ }
55
+ return [];
56
+ }
57
+ function flattenTree(nodes, out = []) {
58
+ if (!Array.isArray(nodes))
59
+ return out;
60
+ for (const node of nodes) {
61
+ if (!node || typeof node !== 'object')
62
+ continue;
63
+ out.push(node);
64
+ flattenTree(node.children, out);
65
+ flattenTree(node.childList, out);
66
+ }
67
+ return out;
68
+ }
69
+ async function listCategories(host) {
70
+ const value = await host.contractRequest({ method: 'GET', path: `${TREE_BASE}/queryList` });
71
+ return flattenTree(value?.data);
72
+ }
73
+ async function listClauses(host, query) {
74
+ const value = await host.contractRequest({
75
+ method: 'GET',
76
+ path: `${INFO_BASE}/getListPage`,
77
+ query: { pageNo: 1, pageSize: 50, ...query },
78
+ });
79
+ return recordsOf(value);
80
+ }
81
+ async function listClauseGroups(host, query) {
82
+ const value = await host.contractRequest({
83
+ method: 'GET',
84
+ path: `${GROUP_BASE}/getListPage`,
85
+ query: { pageNo: 1, pageSize: 50, ...query },
86
+ });
87
+ return recordsOf(value);
88
+ }
89
+ // ---------------------------------------------------------------- 查询类
90
+ export const contractClausePermissionOperation = {
91
+ name: 'contract.clause.permission',
92
+ async execute(_input, { host }) {
93
+ const permission = await assertClausePermission(host);
94
+ const session = await host.getSession();
95
+ return {
96
+ status: 'COMPLETE',
97
+ data: { ...permission, url: clauseLibraryPageUrl(session.baseUrl) },
98
+ };
99
+ },
100
+ };
101
+ export const contractClauseTypeListOperation = new ClauseGatedOperation('contract.clause.types', new ContractReadOperation('contract.clause.types', {
102
+ method: 'GET',
103
+ path: `${TREE_BASE}/queryAllCluseType`,
104
+ shape: (value) => ({ code: value.code, msg: value.msg, types: value.data }),
105
+ }));
106
+ export const contractClauseCheckOperation = {
107
+ name: 'contract.clause.check',
108
+ async execute(input, { host }) {
109
+ await assertClausePermission(host);
110
+ // 判重只允许传 clauseName + belongId;缺 belongId 会静默返回「不存在」,必须在这里拦住。
111
+ const clauseName = requireNonEmptyString(input.clauseName, 'clauseName', 200).trim();
112
+ const belongId = requireId(input.belongId, 'belongId');
113
+ const value = await host.contractRequest({
114
+ method: 'GET',
115
+ path: `${INFO_BASE}/checkData`,
116
+ query: { clauseName, belongId },
117
+ });
118
+ const data = value?.data;
119
+ const exists = data !== null && data !== undefined && data !== '' && data !== false;
120
+ return {
121
+ status: 'COMPLETE',
122
+ data: { clauseName, belongId, exists, raw: data },
123
+ };
124
+ },
125
+ };
126
+ export const contractClauseBrowserOperation = {
127
+ name: 'contract.clause.browser',
128
+ async execute(input, { host }) {
129
+ await assertClausePermission(host);
130
+ const name = requireNonEmptyString(input.name, 'name', 200).trim();
131
+ const value = await host.contractRequest({
132
+ method: 'POST',
133
+ path: `${INFO_BASE}/common/browser/data/clauseInfoBrowser`,
134
+ body: { quickSearchDatas: { name } },
135
+ });
136
+ const rows = Array.isArray(value?.data) ? value.data : recordsOf(value);
137
+ return {
138
+ status: 'COMPLETE',
139
+ data: {
140
+ name,
141
+ clauses: rows.map((row) => ({
142
+ id: row.id,
143
+ name: row.name ?? row.clauseName,
144
+ })),
145
+ hint: rows.length > 1 ? '命中多条时必须让用户确认条款,禁止自动选第一条' : undefined,
146
+ },
147
+ };
148
+ },
149
+ };
150
+ export const contractClauseSubcompanyOperation = {
151
+ name: 'contract.clause.subcompany',
152
+ async execute(input, { host }) {
153
+ await assertClausePermission(host);
154
+ const name = typeof input.name === 'string' ? input.name.trim() : '';
155
+ try {
156
+ const value = await host.contractRequest({
157
+ method: 'POST',
158
+ path: '/api/hrm/common/browser/data/subcompany',
159
+ body: { quickSearchDatas: { name } },
160
+ });
161
+ const rows = Array.isArray(value?.data) ? value.data : recordsOf(value);
162
+ return {
163
+ status: 'COMPLETE',
164
+ data: { source: 'subcompany', subs: rows, hint: '未指定分部时 belongSub 传空字符串 ""' },
165
+ };
166
+ }
167
+ catch (error) {
168
+ // 源资料明确:subcompany 返回 500 时降级到机构树接口。
169
+ if (!(error instanceof ContractCliError) || (error.type !== 'api' && error.type !== 'network'))
170
+ throw error;
171
+ const value = await host.contractRequest({
172
+ method: 'GET',
173
+ path: '/api/hrm/common/getOrgTree',
174
+ query: {
175
+ menuCode: 'termComponent',
176
+ onlySubcompany: 'false',
177
+ containDisableDept: 'false',
178
+ moduleCode: 'CONTRACT',
179
+ virtualId: 1,
180
+ loadCount: 'false',
181
+ checkAllPermission: 'true',
182
+ isMobile: 'false',
183
+ },
184
+ });
185
+ return {
186
+ status: 'COMPLETE',
187
+ data: { source: 'getOrgTree', subs: flattenTree(value?.data), hint: '未指定分部时 belongSub 传空字符串 ""' },
188
+ };
189
+ }
190
+ },
191
+ };
192
+ // ---------------------------------------------------------------- 写操作
193
+ function pairContractType(input) {
194
+ const id = input.contractType;
195
+ const name = input.contractTypeName;
196
+ if ((id === undefined) !== (name === undefined)) {
197
+ throw contractValidationError('contract_type_pair_required', 'contractType 与 contractTypeName 必须成对提交:只传 id 会导致页面合同类型名缺失');
198
+ }
199
+ }
200
+ function clauseBody(input) {
201
+ return bodyFrom(input, [
202
+ 'clauseName', 'clauseNum', 'clauseContent', 'belongId', 'contractType', 'contractTypeName',
203
+ 'clauseVersion', 'clauseGroup', 'clauseStatus', 'clauseForm', 'isSmartCombination',
204
+ ]);
205
+ }
206
+ const categoryCreateSpec = {
207
+ method: 'POST',
208
+ path: `${TREE_BASE}/save`,
209
+ validate(input) {
210
+ requireNonEmptyString(input.clauseName, 'clauseName', 200);
211
+ const parentId = input.parentId === undefined ? '0' : String(input.parentId);
212
+ if (parentId !== '0')
213
+ requireId(parentId, 'parentId');
214
+ const levelNum = input.levelNum === undefined ? (parentId === '0' ? '0' : undefined) : String(input.levelNum);
215
+ if (levelNum === undefined) {
216
+ throw contractValidationError('level_num_required', '子分类必须传 levelNum(父分类 levelNum + 1);顶层分类可省略,固定为 0');
217
+ }
218
+ if (parentId === '0' && levelNum !== '0') {
219
+ throw contractValidationError('level_num_invalid', '顶层分类的 levelNum 必须是 0');
220
+ }
221
+ },
222
+ body: (input) => bodyFrom(input, ['clauseName', 'parentId', 'orderNum', 'clauseStatus', 'isSystem', 'levelNum'], {
223
+ parentId: input.parentId === undefined ? '0' : String(input.parentId),
224
+ orderNum: input.orderNum ?? '1',
225
+ clauseStatus: input.clauseStatus ?? '1',
226
+ isSystem: '0',
227
+ levelNum: input.levelNum === undefined ? '0' : String(input.levelNum),
228
+ }),
229
+ fingerprint: fingerprintFields(['clauseName', 'parentId', 'orderNum', 'clauseStatus', 'levelNum']),
230
+ preview: (input) => ({
231
+ action: '新增条款分类',
232
+ clauseName: input.clauseName,
233
+ parentId: input.parentId ?? '0',
234
+ levelNum: input.levelNum ?? '0',
235
+ warning: 'clauseType 不传(传了会 500);删除分类会级联删除其下条款',
236
+ }),
237
+ async precheck(input, host) {
238
+ const value = await host.contractRequest({
239
+ method: 'GET',
240
+ path: `${TREE_BASE}/checkData`,
241
+ query: { clauseName: input.clauseName },
242
+ });
243
+ const existing = value?.data;
244
+ if (existing !== null && existing !== undefined && existing !== '' && existing !== false) {
245
+ throw contractPolicyError('category_already_exists', '同分类下已存在同名条款分类,禁止重复创建', { clauseName: input.clauseName });
246
+ }
247
+ return { duplicateCheck: 'passed' };
248
+ },
249
+ async readback(_result, input, host) {
250
+ const nodes = await listCategories(host);
251
+ const hit = nodes.find((node) => node.clauseName === input.clauseName || node.name === input.clauseName);
252
+ if (!hit)
253
+ throw new Error('分类树中未找到刚创建的分类');
254
+ return { id: hit.id, clauseName: hit.clauseName ?? hit.name };
255
+ },
256
+ };
257
+ const categoryUpdateSpec = {
258
+ method: 'POST',
259
+ path: `${TREE_BASE}/update`,
260
+ validate(input) {
261
+ requireId(input.id, '分类 id');
262
+ requireNonEmptyString(input.clauseName, 'clauseName', 200);
263
+ },
264
+ body: (input) => bodyFrom(input, ['id', 'clauseName', 'parentId', 'orderNum', 'clauseStatus', 'isSystem', 'levelNum']),
265
+ fingerprint: fingerprintFields(['id', 'clauseName', 'parentId', 'orderNum', 'clauseStatus', 'levelNum']),
266
+ preview: (input) => ({ action: '修改条款分类', id: input.id, clauseName: input.clauseName }),
267
+ async readback(_result, input, host) {
268
+ const nodes = await listCategories(host);
269
+ const hit = nodes.find((node) => String(node.id) === String(input.id));
270
+ if (!hit)
271
+ throw new Error('分类树中未找到被修改的分类');
272
+ return { id: hit.id, clauseName: hit.clauseName ?? hit.name };
273
+ },
274
+ };
275
+ const categoryDeleteSpec = {
276
+ method: 'POST',
277
+ path: `${TREE_BASE}/deletebyid`,
278
+ validate(input) {
279
+ requireId(input.id, '分类 id');
280
+ },
281
+ body: (input) => ({ id: String(input.id) }),
282
+ fingerprint: fingerprintFields(['id']),
283
+ preview: (input) => ({
284
+ action: '删除条款分类',
285
+ id: input.id,
286
+ warning: '删除会级联删除该分类下的条款;必须已获得用户明确同意',
287
+ }),
288
+ async precheck(input, host) {
289
+ const nodes = await listCategories(host);
290
+ const hit = nodes.find((node) => String(node.id) === String(input.id));
291
+ if (!hit)
292
+ throw contractPolicyError('category_not_found', '分类不存在,未发起删除', { id: input.id });
293
+ const clauses = await listClauses(host, { belongId: String(input.id) });
294
+ return {
295
+ clauseName: hit.clauseName ?? hit.name,
296
+ clauseCount: clauses.length,
297
+ warning: clauses.length ? `该分类下仍有 ${clauses.length} 条条款,删除将一并级联删除` : '该分类下未查到条款',
298
+ };
299
+ },
300
+ async readback(_result, input, host) {
301
+ const nodes = await listCategories(host);
302
+ if (nodes.some((node) => String(node.id) === String(input.id))) {
303
+ throw new Error('删除接口返回成功,但分类树中仍能查到该分类');
304
+ }
305
+ return { id: input.id, removed: true };
306
+ },
307
+ };
308
+ const clauseCreateSpec = {
309
+ method: 'POST',
310
+ path: `${INFO_BASE}/save`,
311
+ validate(input) {
312
+ requireNonEmptyString(input.clauseName, 'clauseName', 200);
313
+ // 漏传 clauseNum 时服务端不报错、静默存空编号,必须前置拦截。
314
+ requireNonEmptyString(input.clauseNum, 'clauseNum', 64);
315
+ requireNonEmptyString(input.clauseVersion, 'clauseVersion', 32);
316
+ requireId(input.belongId, 'belongId');
317
+ if (input.clauseGroup === undefined || String(input.clauseGroup) === '') {
318
+ throw contractValidationError('clause_group_required', 'clauseGroup 必传(无所属条款组时传 "-1"),缺失服务端 500');
319
+ }
320
+ pairContractType(input);
321
+ },
322
+ body: (input) => clauseBody(input),
323
+ fingerprint: fingerprintFields([
324
+ 'clauseName', 'clauseNum', 'clauseContent', 'belongId', 'contractType', 'contractTypeName',
325
+ 'clauseVersion', 'clauseGroup', 'clauseStatus',
326
+ ]),
327
+ preview: (input) => ({
328
+ action: '新增条款',
329
+ clauseName: input.clauseName,
330
+ clauseNum: input.clauseNum,
331
+ belongId: input.belongId,
332
+ clauseVersion: input.clauseVersion,
333
+ clauseGroup: input.clauseGroup,
334
+ contractType: input.contractType,
335
+ contractTypeName: input.contractTypeName,
336
+ }),
337
+ async precheck(input, host) {
338
+ const value = await host.contractRequest({
339
+ method: 'GET',
340
+ path: `${INFO_BASE}/checkData`,
341
+ query: { clauseName: input.clauseName, belongId: String(input.belongId) },
342
+ });
343
+ const existing = value?.data;
344
+ if (existing !== null && existing !== undefined && existing !== '' && existing !== false) {
345
+ throw contractPolicyError('clause_already_exists', '同一分类下已存在同名条款;判重依据是名称,不是编号或内容', {
346
+ clauseName: input.clauseName,
347
+ belongId: input.belongId,
348
+ });
349
+ }
350
+ return { duplicateCheck: 'passed' };
351
+ },
352
+ async readback(_result, input, host) {
353
+ const rows = await listClauses(host, { clauseName: input.clauseName, belongId: String(input.belongId) });
354
+ const hit = rows.find((row) => (row.clauseName ?? row.name) === input.clauseName);
355
+ if (!hit)
356
+ throw new Error('条款列表中未找到刚创建的条款');
357
+ if (String(hit.clauseNum ?? '') !== String(input.clauseNum)) {
358
+ throw new Error(`编号未落库:期望 ${input.clauseNum},实际 ${hit.clauseNum ?? '(空)'}`);
359
+ }
360
+ return { id: hit.id, clauseName: hit.clauseName ?? hit.name, clauseNum: hit.clauseNum };
361
+ },
362
+ };
363
+ const clauseUpdateSpec = {
364
+ method: 'POST',
365
+ path: `${INFO_BASE}/update`,
366
+ validate(input) {
367
+ requireId(input.id, '条款 id');
368
+ if (input.clauseNum !== undefined)
369
+ requireNonEmptyString(input.clauseNum, 'clauseNum', 64);
370
+ pairContractType(input);
371
+ },
372
+ body: (input) => bodyFrom(input, [
373
+ 'id', 'clauseName', 'clauseNum', 'clauseContent', 'belongId', 'contractType', 'contractTypeName',
374
+ 'clauseVersion', 'clauseGroup', 'clauseStatus', 'clauseForm', 'isSmartCombination',
375
+ ]),
376
+ fingerprint: fingerprintFields([
377
+ 'id', 'clauseName', 'clauseNum', 'clauseContent', 'belongId', 'contractType', 'contractTypeName',
378
+ 'clauseVersion', 'clauseGroup', 'clauseStatus',
379
+ ]),
380
+ preview: (input) => ({ action: '修改条款', id: input.id, clauseName: input.clauseName, clauseNum: input.clauseNum }),
381
+ async readback(_result, input, host) {
382
+ if (!input.clauseName)
383
+ return { skipped: '未提供 clauseName,无法按名称回读' };
384
+ const rows = await listClauses(host, {
385
+ clauseName: input.clauseName,
386
+ ...(input.belongId ? { belongId: String(input.belongId) } : {}),
387
+ });
388
+ const hit = rows.find((row) => String(row.id) === String(input.id));
389
+ if (!hit)
390
+ throw new Error('条款列表中未找到被修改的条款');
391
+ return { id: hit.id, clauseNum: hit.clauseNum, clauseStatus: hit.clauseStatus };
392
+ },
393
+ };
394
+ const clauseDeleteSpec = {
395
+ method: 'POST',
396
+ path: `${INFO_BASE}/deletebyid`,
397
+ validate(input) {
398
+ requireId(input.id, '条款 id');
399
+ },
400
+ body: (input) => ({ id: String(input.id) }),
401
+ fingerprint: fingerprintFields(['id']),
402
+ preview: (input) => ({ action: '删除条款', id: input.id, clauseName: input.clauseName }),
403
+ async readback(_result, input, host) {
404
+ if (!input.clauseName)
405
+ return { skipped: '未提供 clauseName,删除接口对不存在的 id 也会返回成功,建议补 clauseName 复核' };
406
+ const rows = await listClauses(host, {
407
+ clauseName: input.clauseName,
408
+ ...(input.belongId ? { belongId: String(input.belongId) } : {}),
409
+ });
410
+ if (rows.some((row) => String(row.id) === String(input.id))) {
411
+ throw new Error('删除接口返回成功,但条款列表中仍能查到该条款');
412
+ }
413
+ return { id: input.id, removed: true };
414
+ },
415
+ };
416
+ const groupCreateSpec = {
417
+ method: 'POST',
418
+ path: `${GROUP_BASE}/save`,
419
+ validate(input) {
420
+ requireNonEmptyString(input.clauseName, 'clauseName', 200);
421
+ requireNonEmptyString(input.clauseContent, 'clauseContent', 4000);
422
+ if (!/^\d+(,\d+)*$/u.test(input.clauseContent)) {
423
+ throw contractValidationError('clause_content_invalid', 'clauseContent 必须是逗号分隔的条款 id 字符串(先用 contract.clause.browser 取 id)');
424
+ }
425
+ if (typeof input.belongSub !== 'string') {
426
+ throw contractValidationError('belong_sub_required', 'belongSub 必传字符串;未指定分部时传空字符串 "",缺失服务端 500');
427
+ }
428
+ pairContractType(input);
429
+ },
430
+ body: (input) => bodyFrom(input, [
431
+ 'clauseName', 'clauseNum', 'belongId', 'contractType', 'contractTypeName', 'clauseStatus', 'clauseContent', 'belongSub',
432
+ ], { belongSub: input.belongSub }),
433
+ fingerprint: fingerprintFields([
434
+ 'clauseName', 'clauseNum', 'clauseContent', 'belongId', 'belongSub', 'contractType', 'contractTypeName', 'clauseStatus',
435
+ ]),
436
+ preview: (input) => ({
437
+ action: '新增条款组',
438
+ clauseName: input.clauseName,
439
+ clauseIds: input.clauseContent,
440
+ belongSub: input.belongSub || '(不分部)',
441
+ }),
442
+ async readback(_result, input, host) {
443
+ // checkData 对确实存在的组名也会返回「不存在」,只能用 list 自行比对。
444
+ const rows = await listClauseGroups(host, { clauseName: input.clauseName });
445
+ const hit = rows.find((row) => (row.clauseName ?? row.name) === input.clauseName);
446
+ if (!hit)
447
+ throw new Error('条款组列表中未找到刚创建的条款组');
448
+ return { id: hit.id, clauseName: hit.clauseName ?? hit.name, clauseContent: hit.clauseContent };
449
+ },
450
+ };
451
+ const groupUpdateSpec = {
452
+ method: 'POST',
453
+ path: `${GROUP_BASE}/update`,
454
+ validate(input) {
455
+ requireId(input.id, '条款组 id');
456
+ requireNonEmptyString(input.clauseContent, 'clauseContent', 4000);
457
+ if (!/^\d+(,\d+)*$/u.test(input.clauseContent)) {
458
+ throw contractValidationError('clause_content_invalid', 'clauseContent 必须是逗号分隔的条款 id 字符串');
459
+ }
460
+ if (input.belongSub !== undefined && typeof input.belongSub !== 'string') {
461
+ throw contractValidationError('belong_sub_invalid', 'belongSub 必须是字符串;未指定分部时传空字符串 ""');
462
+ }
463
+ pairContractType(input);
464
+ },
465
+ body: (input) => bodyFrom(input, [
466
+ 'id', 'clauseName', 'clauseNum', 'belongId', 'contractType', 'contractTypeName', 'clauseStatus', 'clauseContent', 'belongSub',
467
+ ]),
468
+ fingerprint: fingerprintFields([
469
+ 'id', 'clauseName', 'clauseNum', 'clauseContent', 'belongId', 'belongSub', 'contractType', 'contractTypeName', 'clauseStatus',
470
+ ]),
471
+ preview: (input) => ({ action: '修改条款组', id: input.id, clauseName: input.clauseName, clauseIds: input.clauseContent }),
472
+ async readback(_result, input, host) {
473
+ if (!input.clauseName)
474
+ return { skipped: '未提供 clauseName,无法按名称回读' };
475
+ const rows = await listClauseGroups(host, { clauseName: input.clauseName });
476
+ const hit = rows.find((row) => String(row.id) === String(input.id));
477
+ if (!hit)
478
+ throw new Error('条款组列表中未找到被修改的条款组');
479
+ return { id: hit.id, clauseContent: hit.clauseContent };
480
+ },
481
+ };
482
+ const groupDeleteSpec = {
483
+ method: 'POST',
484
+ path: `${GROUP_BASE}/deletebyid`,
485
+ validate(input) {
486
+ requireId(input.id, '条款组 id');
487
+ },
488
+ body: (input) => ({ id: String(input.id) }),
489
+ fingerprint: fingerprintFields(['id']),
490
+ preview: (input) => ({ action: '删除条款组', id: input.id, clauseName: input.clauseName }),
491
+ async readback(_result, input, host) {
492
+ if (!input.clauseName)
493
+ return { skipped: '未提供 clauseName,删除接口对不存在的 id 也会返回成功' };
494
+ const rows = await listClauseGroups(host, { clauseName: input.clauseName });
495
+ if (rows.some((row) => String(row.id) === String(input.id))) {
496
+ throw new Error('删除接口返回成功,但条款组列表中仍能查到该条款组');
497
+ }
498
+ return { id: input.id, removed: true };
499
+ },
500
+ };
501
+ function writePair(name, applyName, spec) {
502
+ return [
503
+ new ClauseGatedOperation(name, new ContractWritePrepareOperation(name, applyName, spec)),
504
+ new ClauseGatedOperation(applyName, new ContractWriteApplyOperation(applyName, spec)),
505
+ ];
506
+ }
507
+ export const contractClauseLibraryOperations = [
508
+ contractClausePermissionOperation,
509
+ contractClauseTypeListOperation,
510
+ contractClauseCheckOperation,
511
+ contractClauseBrowserOperation,
512
+ contractClauseSubcompanyOperation,
513
+ ...writePair('contract.clause.category.create.prepare', 'contract.clause.category.create.apply', categoryCreateSpec),
514
+ ...writePair('contract.clause.category.update.prepare', 'contract.clause.category.update.apply', categoryUpdateSpec),
515
+ ...writePair('contract.clause.category.delete.prepare', 'contract.clause.category.delete.apply', categoryDeleteSpec),
516
+ ...writePair('contract.clause.create.prepare', 'contract.clause.create.apply', clauseCreateSpec),
517
+ ...writePair('contract.clause.update.prepare', 'contract.clause.update.apply', clauseUpdateSpec),
518
+ ...writePair('contract.clause.delete.prepare', 'contract.clause.delete.apply', clauseDeleteSpec),
519
+ ...writePair('contract.clause.group.create.prepare', 'contract.clause.group.create.apply', groupCreateSpec),
520
+ ...writePair('contract.clause.group.update.prepare', 'contract.clause.group.update.apply', groupUpdateSpec),
521
+ ...writePair('contract.clause.group.delete.prepare', 'contract.clause.group.delete.apply', groupDeleteSpec),
522
+ ];