weaver-work-cli 0.1.7 → 0.1.20

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 (264) hide show
  1. package/README.md +11 -11
  2. package/dist/cmd/action.js +76 -0
  3. package/dist/cmd/index.js +2 -0
  4. package/dist/cmd/refs/index.js +103 -0
  5. package/dist/cmd/register.js +31 -0
  6. package/dist/cmd/root.js +1 -0
  7. package/dist/cmd/setup/index.js +25 -5
  8. package/dist/cmd/skills/index.js +37 -5
  9. package/dist/core/connector.js +54 -0
  10. package/dist/core/context.js +2 -1
  11. package/dist/core/input.js +48 -0
  12. package/dist/core/output.js +298 -3
  13. package/dist/core/refs.js +432 -0
  14. package/dist/core/state.js +26 -0
  15. package/dist/internal/e10/auth/commands.js +2 -2
  16. package/dist/internal/e10/auth/session.js +14 -0
  17. package/dist/internal/e10/auth/xiaoe.js +116 -51
  18. package/dist/internal/e10/request-runtime.js +5 -0
  19. package/dist/internal/skills/install.js +148 -28
  20. package/dist/internal/skills/reader.js +12 -9
  21. package/dist/shortcuts/blog/continuation.js +74 -0
  22. package/dist/shortcuts/blog/errors.js +60 -0
  23. package/dist/shortcuts/blog/host.js +175 -0
  24. package/dist/shortcuts/blog/index.js +324 -0
  25. package/dist/shortcuts/blog/manifest.js +415 -0
  26. package/dist/shortcuts/blog/operations/comment.js +125 -0
  27. package/dist/shortcuts/blog/operations/comments.js +31 -0
  28. package/dist/shortcuts/blog/operations/edit.js +131 -0
  29. package/dist/shortcuts/blog/operations/export.js +46 -0
  30. package/dist/shortcuts/blog/operations/like.js +80 -0
  31. package/dist/shortcuts/blog/operations/publish.js +157 -0
  32. package/dist/shortcuts/blog/operations/query-user.js +58 -0
  33. package/dist/shortcuts/blog/operations/query.js +96 -0
  34. package/dist/shortcuts/blog/operations/registry.js +54 -0
  35. package/dist/shortcuts/blog/operations/remind.js +176 -0
  36. package/dist/shortcuts/blog/operations/shared.js +330 -0
  37. package/dist/shortcuts/blog/operations/types.js +16 -0
  38. package/dist/shortcuts/blog/operations.js +9 -0
  39. package/dist/shortcuts/caizhilian/continuation.js +70 -0
  40. package/dist/shortcuts/caizhilian/errors.js +53 -0
  41. package/dist/shortcuts/caizhilian/host.js +190 -0
  42. package/dist/shortcuts/caizhilian/index.js +186 -0
  43. package/dist/shortcuts/caizhilian/manifest.js +42 -0
  44. package/dist/shortcuts/caizhilian/operations/api.js +801 -0
  45. package/dist/shortcuts/caizhilian/operations/confirm.js +75 -0
  46. package/dist/shortcuts/caizhilian/operations/files.js +306 -0
  47. package/dist/shortcuts/caizhilian/operations/form.js +170 -0
  48. package/dist/shortcuts/caizhilian/operations/handlers/collab.js +611 -0
  49. package/dist/shortcuts/caizhilian/operations/handlers/document.js +890 -0
  50. package/dist/shortcuts/caizhilian/operations/handlers/file-collection.js +346 -0
  51. package/dist/shortcuts/caizhilian/operations/handlers/file-upload.js +192 -0
  52. package/dist/shortcuts/caizhilian/operations/handlers/fileops.js +570 -0
  53. package/dist/shortcuts/caizhilian/operations/handlers/folder.js +969 -0
  54. package/dist/shortcuts/caizhilian/operations/handlers/search.js +318 -0
  55. package/dist/shortcuts/caizhilian/operations/handlers/setting-attach.js +294 -0
  56. package/dist/shortcuts/caizhilian/operations/handlers/setting-backup.js +423 -0
  57. package/dist/shortcuts/caizhilian/operations/handlers/setting-encrypt.js +238 -0
  58. package/dist/shortcuts/caizhilian/operations/handlers/setting-storage.js +364 -0
  59. package/dist/shortcuts/caizhilian/operations/handlers/system.js +106 -0
  60. package/dist/shortcuts/caizhilian/operations/registry.js +151 -0
  61. package/dist/shortcuts/caizhilian/operations/shared.js +408 -0
  62. package/dist/shortcuts/caizhilian/operations/specs.js +623 -0
  63. package/dist/shortcuts/caizhilian/operations/types.js +57 -0
  64. package/dist/shortcuts/caizhilian/operations.js +21 -0
  65. package/dist/shortcuts/contract/continuation.js +70 -0
  66. package/dist/shortcuts/contract/errors.js +62 -0
  67. package/dist/shortcuts/contract/host.js +205 -0
  68. package/dist/shortcuts/contract/index.js +318 -0
  69. package/dist/shortcuts/contract/manifest.js +596 -0
  70. package/dist/shortcuts/contract/operations/clause-reference.js +78 -0
  71. package/dist/shortcuts/contract/operations/form-info.js +371 -0
  72. package/dist/shortcuts/contract/operations/read.js +118 -0
  73. package/dist/shortcuts/contract/operations/registry.js +43 -0
  74. package/dist/shortcuts/contract/operations/request.js +300 -0
  75. package/dist/shortcuts/contract/operations/shared.js +133 -0
  76. package/dist/shortcuts/contract/operations/subject.js +157 -0
  77. package/dist/shortcuts/contract/operations/template.js +81 -0
  78. package/dist/shortcuts/contract/operations/types.js +7 -0
  79. package/dist/shortcuts/contract/operations/workflow.js +52 -0
  80. package/dist/shortcuts/contract/operations/write.js +131 -0
  81. package/dist/shortcuts/contract/operations.js +8 -0
  82. package/dist/shortcuts/hrm/index.js +83 -2
  83. package/dist/shortcuts/hrm/operations/employee.js +160 -30
  84. package/dist/shortcuts/hrm/operations/org.js +17 -3
  85. package/dist/shortcuts/hrm/operations/position.js +18 -2
  86. package/dist/shortcuts/index.js +5 -1
  87. package/dist/shortcuts/invoice/index.js +74 -36
  88. package/dist/shortcuts/invoice/manifest.js +674 -4
  89. package/dist/shortcuts/invoice/markdown.js +172 -0
  90. package/dist/shortcuts/invoice/operations/add.js +3 -3
  91. package/dist/shortcuts/invoice/operations/delete.js +2 -2
  92. package/dist/shortcuts/invoice/operations/get.js +10 -2
  93. package/dist/shortcuts/invoice/operations/import.js +2 -2
  94. package/dist/shortcuts/invoice/operations/registry.js +8 -1
  95. package/dist/shortcuts/invoice/operations/reim-auto.js +719 -0
  96. package/dist/shortcuts/invoice/operations/reim.js +85 -2
  97. package/dist/shortcuts/invoice/operations/shared.js +75 -8
  98. package/dist/shortcuts/invoice/operations/update.js +2 -2
  99. package/dist/shortcuts/invoice/operations/upload-and-validate.js +93 -0
  100. package/dist/shortcuts/invoice/operations/validate-preview.js +2 -1
  101. package/dist/shortcuts/invoice/projection.js +328 -0
  102. package/dist/shortcuts/meeting/host.js +18 -1
  103. package/dist/shortcuts/meeting/manifest.js +30 -18
  104. package/dist/shortcuts/meeting/operations/eb/catalog.js +390 -0
  105. package/dist/shortcuts/meeting/operations/eb/conflict.js +389 -0
  106. package/dist/shortcuts/meeting/operations/eb/factory.js +389 -0
  107. package/dist/shortcuts/meeting/operations/eb/index.js +22 -0
  108. package/dist/shortcuts/meeting/operations/env.js +8 -1
  109. package/dist/shortcuts/meeting/operations/registry.js +2 -0
  110. package/dist/shortcuts/meeting/operations/signs.js +216 -2
  111. package/dist/shortcuts/workflow/endpoints.js +2 -1
  112. package/dist/shortcuts/workflow/errors.js +8 -2
  113. package/dist/shortcuts/workflow/host.js +6 -3
  114. package/dist/shortcuts/workflow/operations/form.js +931 -533
  115. package/dist/shortcuts/workflow/operations/read.js +462 -81
  116. package/dist/shortcuts/workflow/operations/shared.js +44 -0
  117. package/dist/shortcuts/workflow/operations/write.js +760 -56
  118. package/dist/shortcuts/workflow/operations.js +36 -10
  119. package/docs/_catalog.md +6 -0
  120. package/docs/agent-invoice.md +5 -1
  121. package/docs/agent-io-channel-design.md +468 -0
  122. package/docs/agent-skill-install.md +9 -4
  123. package/docs/blog.md +123 -0
  124. package/docs/caizhilian.md +304 -0
  125. package/docs/contract.md +91 -0
  126. package/docs/e10-auth.md +2 -2
  127. package/docs/hrm.md +19 -9
  128. package/docs/invoice.md +5 -1
  129. package/docs/meeting.md +1 -1
  130. package/docs/operation-manual.md +15 -3
  131. package/docs/skill-review-2026-09-19.md +2 -2
  132. package/package.json +2 -2
  133. package/scripts/package-skill.mjs +33 -20
  134. package/skill-template/business-info.json +113 -14
  135. package/skill-template/domains/blog.md +24 -0
  136. package/skill-template/domains/caizhilian.md +22 -0
  137. package/skill-template/domains/jinchengda.md +23 -0
  138. package/skill-template/domains/meeting.md +1 -1
  139. package/skill-template/domains/workflow.md +1 -1
  140. package/skill-template/skill-template.md +1 -1
  141. package/skills/weaver-e10-blog/SKILL.md +111 -0
  142. package/skills/weaver-e10-blog/references/blog-comment.md +51 -0
  143. package/skills/weaver-e10-blog/references/blog-comments.md +39 -0
  144. package/skills/weaver-e10-blog/references/blog-default-permission.md +38 -0
  145. package/skills/weaver-e10-blog/references/blog-disabled-capabilities.md +11 -0
  146. package/skills/weaver-e10-blog/references/blog-edit.md +51 -0
  147. package/skills/weaver-e10-blog/references/blog-export.md +42 -0
  148. package/skills/weaver-e10-blog/references/blog-like.md +50 -0
  149. package/skills/weaver-e10-blog/references/blog-publish.md +52 -0
  150. package/skills/weaver-e10-blog/references/blog-query-user.md +45 -0
  151. package/skills/weaver-e10-blog/references/blog-query.md +49 -0
  152. package/skills/weaver-e10-blog/references/blog-remind.md +51 -0
  153. package/skills/weaver-e10-blog/references/blog-resolve-users.md +38 -0
  154. package/skills/weaver-e10-blog/references/source-manifest.json +1540 -0
  155. package/skills/weaver-e10-caizhilian/SKILL.md +216 -0
  156. package/skills/weaver-e10-caizhilian/references/agent-entry.md +106 -0
  157. package/skills/weaver-e10-caizhilian/references/collaboration.md +112 -0
  158. package/skills/weaver-e10-caizhilian/references/document.md +111 -0
  159. package/skills/weaver-e10-caizhilian/references/file-collection.md +136 -0
  160. package/skills/weaver-e10-caizhilian/references/file-upload.md +309 -0
  161. package/skills/weaver-e10-caizhilian/references/files.md +120 -0
  162. package/skills/weaver-e10-caizhilian/references/folder.md +118 -0
  163. package/skills/weaver-e10-caizhilian/references/org-browser.md +104 -0
  164. package/skills/weaver-e10-caizhilian/references/setting-attach.md +410 -0
  165. package/skills/weaver-e10-caizhilian/references/setting-backup.md +372 -0
  166. package/skills/weaver-e10-caizhilian/references/setting-encrypt.md +399 -0
  167. package/skills/weaver-e10-caizhilian/references/setting-storage.md +603 -0
  168. package/skills/weaver-e10-caizhilian/references/source-manifest.json +5079 -0
  169. package/skills/weaver-e10-caizhilian/references/withheld.md +93 -0
  170. package/skills/weaver-e10-caizhilian/references/write-protocol.md +120 -0
  171. package/skills/weaver-e10-calendar/SKILL.md +4 -3
  172. package/skills/weaver-e10-ebuilder-form/SKILL.md +4 -9
  173. package/skills/weaver-e10-ebuilder-form/references/context-routing.md +0 -9
  174. package/skills/weaver-e10-ebuilder-form/references/custom-api.md +1 -5
  175. package/skills/weaver-e10-ebuilder-form/references/fields-browser.md +1 -5
  176. package/skills/weaver-e10-ebuilder-form/references/list-nlist.md +1 -5
  177. package/skills/weaver-e10-ebuilder-form/references/openapi-read.md +1 -5
  178. package/skills/weaver-e10-ebuilder-form/references/openapi-write.md +1 -5
  179. package/skills/weaver-e10-esb/SKILL.md +2 -2
  180. package/skills/weaver-e10-esb/references/source-manifest.json +9 -9
  181. package/skills/weaver-e10-hrm/SKILL.md +54 -6
  182. package/skills/weaver-e10-hrm/references/employee.md +89 -15
  183. package/skills/weaver-e10-hrm/references/org.md +7 -4
  184. package/skills/weaver-e10-hrm/references/position.md +14 -7
  185. package/skills/weaver-e10-hrm/references/source-manifest.json +1 -1
  186. package/skills/weaver-e10-jinchengda/SKILL.md +166 -0
  187. package/skills/weaver-e10-jinchengda/references/contract-agent-entry.md +82 -0
  188. package/skills/weaver-e10-jinchengda/references/contract-clause-recommender.md +69 -0
  189. package/skills/weaver-e10-jinchengda/references/contract-clause-reference-save.md +78 -0
  190. package/skills/weaver-e10-jinchengda/references/contract-disabled-capabilities.md +27 -0
  191. package/skills/weaver-e10-jinchengda/references/contract-request-status.md +71 -0
  192. package/skills/weaver-e10-jinchengda/references/contract-request-write.md +94 -0
  193. package/skills/weaver-e10-jinchengda/references/contract-signing-subjects.md +89 -0
  194. package/skills/weaver-e10-jinchengda/references/contract-subject-create.md +77 -0
  195. package/skills/weaver-e10-jinchengda/references/contract-template-selector.md +66 -0
  196. package/skills/weaver-e10-jinchengda/references/contract-workflow-discovery.md +94 -0
  197. package/skills/weaver-e10-jinchengda/references/source-manifest.json +259 -0
  198. package/skills/weaver-e10-jiuchuanhui/SKILL.md +5 -11
  199. package/skills/weaver-e10-jucailin/SKILL.md +4 -3
  200. package/skills/weaver-e10-mail/SKILL.md +4 -11
  201. package/skills/weaver-e10-meeting/SKILL.md +66 -32
  202. package/skills/weaver-e10-meeting/references/meeting-change.md +5 -2
  203. package/skills/weaver-e10-meeting/references/meeting-create.md +2 -1
  204. package/skills/weaver-e10-meeting/references/meeting-eb.md +114 -0
  205. package/skills/weaver-e10-meeting/references/meeting-lifecycle.md +9 -8
  206. package/skills/weaver-e10-meeting/references/meeting-receipts-signs.md +35 -7
  207. package/skills/weaver-e10-meeting/references/meeting-update.md +1 -1
  208. package/skills/weaver-e10-okr/SKILL.md +6 -11
  209. package/skills/weaver-e10-okr/references/source-manifest.json +3 -3
  210. package/skills/weaver-e10-plan/SKILL.md +3 -3
  211. package/skills/weaver-e10-plan/references/plan-collect-and-compose.md +1 -1
  212. package/skills/weaver-e10-plan/references/plan-overview-and-routing.md +1 -1
  213. package/skills/weaver-e10-plan/references/source-manifest.json +13 -13
  214. package/skills/weaver-e10-qiyecheng/SKILL.md +4 -10
  215. package/skills/weaver-e10-qiyecheng/references/source-manifest.json +9 -9
  216. package/skills/weaver-e10-shared/SKILL.md +36 -25
  217. package/skills/weaver-e10-shared/references/e10-auth-and-session.md +10 -31
  218. package/skills/weaver-e10-shared/references/json-output-contract.md +20 -11
  219. package/skills/weaver-e10-shijingran/SKILL.md +2 -1
  220. package/skills/weaver-e10-shijingran/references/source-manifest.json +9 -9
  221. package/skills/weaver-e10-skill-maker/SKILL.md +4 -10
  222. package/skills/weaver-e10-skill-maker/references/business-skill-generation.md +5 -3
  223. package/skills/weaver-e10-skill-maker/references/module-cli-generation.md +12 -27
  224. package/skills/weaver-e10-skill-maker/references/module-gap-audit-and-repair.md +17 -5
  225. package/skills/weaver-e10-skill-maker/references/source-update-detection.md +4 -27
  226. package/skills/weaver-e10-wenshuding/SKILL.md +5 -16
  227. package/skills/weaver-e10-wenshuding/references/source-manifest.json +7 -7
  228. package/skills/weaver-e10-workflow/SKILL.md +32 -37
  229. package/skills/weaver-e10-workflow/references/source-manifest.json +40 -77
  230. package/skills/weaver-e10-workflow/references/workflow-batch.md +90 -29
  231. package/skills/weaver-e10-workflow/references/workflow-create.md +79 -109
  232. package/skills/weaver-e10-workflow/references/workflow-memory.md +19 -9
  233. package/skills/weaver-e10-workflow/references/workflow-operate.md +2 -2
  234. package/skills/weaver-e10-workflow/references/workflow-query.md +37 -20
  235. package/skills/weaver-e10-workflow/references/workflow-share.md +18 -2
  236. package/skills/weaver-e10-workflow/references/workflow-view.md +4 -4
  237. package/skills/weaver-e10-yepiaotong/SKILL.md +75 -39
  238. package/skills/weaver-e10-yepiaotong/references/invoice-detail.md +22 -1
  239. package/skills/weaver-e10-yepiaotong/references/invoice-enterprise-list.md +3 -1
  240. package/skills/weaver-e10-yepiaotong/references/invoice-issuing.md +5 -5
  241. package/skills/weaver-e10-yepiaotong/references/invoice-output-view.md +135 -0
  242. package/skills/weaver-e10-yepiaotong/references/invoice-personal-list.md +15 -3
  243. package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +1 -1
  244. package/skills/weaver-e10-yepiaotong/references/invoice-summarize.py +217 -0
  245. package/skills/weaver-e10-yepiaotong/references/invoice-upload-and-validate.md +88 -0
  246. package/skills/weaver-e10-yepiaotong/references/invoice-validation-preview.md +7 -2
  247. package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +90 -10
  248. package/skills/weaver-e10-yepiaotong/references/reim-examples.md +1 -0
  249. package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +70 -49
  250. package/skills/weaver-e10-yepiaotong/references/reim-fast-path.md +119 -0
  251. package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +55 -36
  252. package/skills/weaver-e10-yepiaotong/references/reim-matching-rules.md +4 -0
  253. package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +149 -0
  254. package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +125 -5
  255. package/skills/weaver-e10-yepiaotong/references/source-manifest.json +430 -63
  256. package/skills/weaver-e10-yimiaoban/SKILL.md +4 -12
  257. package/skills/weaver-e10-yimiaoban/references/source-manifest.json +3 -3
  258. package/skills/weaver-e10-ziguanjia/SKILL.md +2 -1
  259. package/skills/weaver-e10-ziguanjia/references/ziguanjia-agent-entry.md +3 -3
  260. package/tools/weaver-skill-detector-1.0.13/SKILL.md +9 -9
  261. package/tools/weaver-skill-detector-1.0.13/references/checklist.md +3 -3
  262. package/tools/weaver-skill-detector-1.0.13/scripts/__pycache__/validate_skill.cpython-313.pyc +0 -0
  263. package/tools/weaver-skill-detector-1.0.13/scripts/validate_skill.py +98 -91
  264. package/scripts/sync-connector-skills.mjs +0 -172
@@ -0,0 +1,318 @@
1
+ import { hasNextPage, optionalId, optionalText, parsePage, resolveTimeRange, toBoolean, } from '../shared.js';
2
+ import { caizhilianSuccess } from '../types.js';
3
+ /**
4
+ * 检索类只读操作(1:1 对应源 scripts/search_plugins.py 的 10 个 plugin
5
+ * + scripts/doc_compare_plugins.py 的 search_doc_compare_documents)。
6
+ */
7
+ /** 源 _plugin_helpers.DOC_OUTPUT_DIRECT_KEYS。 */
8
+ const DOC_OUTPUT_DIRECT_KEYS = [
9
+ 'id',
10
+ 'name',
11
+ 'docCreateTime',
12
+ 'docLastUpdateTime',
13
+ 'docAuthorId',
14
+ 'docAuthorName',
15
+ 'docCreatorId',
16
+ 'docCreatorName',
17
+ 'folderPathName',
18
+ 'belongFolderIds',
19
+ ];
20
+ function isRecord(value) {
21
+ return !!value && typeof value === 'object' && !Array.isArray(value);
22
+ }
23
+ /** 源 get_nested_value(data, "data.list"):取不到或非列表时按空列表处理。 */
24
+ function nestedList(response, ...keys) {
25
+ let current = response;
26
+ for (const key of keys) {
27
+ if (!isRecord(current))
28
+ return [];
29
+ current = current[key];
30
+ }
31
+ return Array.isArray(current) ? current : [];
32
+ }
33
+ function nestedValue(response, ...keys) {
34
+ let current = response;
35
+ for (const key of keys) {
36
+ if (!isRecord(current))
37
+ return undefined;
38
+ current = current[key];
39
+ }
40
+ return current;
41
+ }
42
+ /** 源 _plugin_helpers.build_search_doc:白名单直取字段 + docMetadata 派生字段。 */
43
+ export function buildSearchDoc(item) {
44
+ const doc = {};
45
+ for (const key of DOC_OUTPUT_DIRECT_KEYS)
46
+ doc[key] = item[key] ?? null;
47
+ const meta = isRecord(item.docMetadata) ? item.docMetadata : {};
48
+ doc.type = meta.type ?? '';
49
+ doc.size = meta.fileSize ?? '';
50
+ doc.docStatus = meta.docStatus ?? null;
51
+ doc.docStatusName = meta.docStatusName ?? item.docStatusName ?? '';
52
+ return doc;
53
+ }
54
+ /** 文档检索结果分页封装(源 search_documents / search_doc_compare_documents 共用输出结构)。 */
55
+ function documentPage(action, response, pageNo, pageSize) {
56
+ const raw = nestedList(response, 'data', 'list');
57
+ return caizhilianSuccess(action, {
58
+ total: nestedValue(response, 'data', 'total') ?? null,
59
+ page_no: pageNo,
60
+ page_size: pageSize,
61
+ has_next: raw.length >= pageSize,
62
+ documents: raw.filter(isRecord).map(buildSearchDoc),
63
+ });
64
+ }
65
+ /** 源 create_time 条件:不支持的取值直接报错(源 resolve_condition_time_range 返回 None 分支)。 */
66
+ function timeCondition(args, field = 'create_time') {
67
+ const value = optionalText(args[field], field);
68
+ if (!value)
69
+ return undefined;
70
+ return { id: field, type: 'date', value: resolveTimeRange(value, field) };
71
+ }
72
+ // ── caizhilian.document.search ────────────────────────────
73
+ async function searchDocuments(args, env) {
74
+ const action = 'caizhilian.document.search';
75
+ const { pageNo, pageSize } = parsePage(args, 40);
76
+ const body = {
77
+ viewType: 'list',
78
+ dimension: 'ALL',
79
+ includeBelongFolders: true,
80
+ order: { property: 'default', direction: 'ASC' },
81
+ searchType: 'all',
82
+ isSearch: true,
83
+ pageNo,
84
+ pageSize,
85
+ };
86
+ const keywords = optionalText(args.keywords, 'keywords');
87
+ if (keywords) {
88
+ body.keywords = keywords;
89
+ body.filter = { keywords, type: 'all' };
90
+ }
91
+ else {
92
+ body.filter = { keywords: '', type: 'all' };
93
+ }
94
+ const folderId = optionalId(args.folder_id, 'folder_id');
95
+ if (folderId !== undefined) {
96
+ body.folder = { id: folderId };
97
+ // 源逻辑:仅当调用方显式传了 include_sub_folder 才带上该字段。
98
+ if (args.include_sub_folder !== undefined && args.include_sub_folder !== null) {
99
+ body.includeSubFolder = toBoolean(args.include_sub_folder);
100
+ }
101
+ }
102
+ const conditions = [];
103
+ const createTime = timeCondition(args);
104
+ if (createTime)
105
+ conditions.push(createTime);
106
+ const creator = optionalId(args.creator_user_id, 'creator_user_id');
107
+ if (creator)
108
+ conditions.push({ id: 'creator', operate: 'eq', type: 'array', value: creator });
109
+ body.conditions = conditions;
110
+ const response = await env.host.request({ method: 'POST', path: '/api/doc/documents/list', body, operation: action });
111
+ return documentPage(action, response, pageNo, pageSize);
112
+ }
113
+ // ── caizhilian.folder.search-virtual ──────────────────────
114
+ /** 源 SearchVirtualFoldersPlugin._CONTENT_RE:content 形如 "名称[路径]"。 */
115
+ const VIRTUAL_CONTENT_RE = /^([^\[]+)\[(.+)\]$/;
116
+ async function searchVirtualFolders(args, env) {
117
+ const action = 'caizhilian.folder.search-virtual';
118
+ const { pageNo, pageSize } = parsePage(args, 50);
119
+ const name = optionalText(args.name, 'name') ?? '';
120
+ const body = {
121
+ browserMultiple: true,
122
+ id: '400',
123
+ option: '',
124
+ formDatas: {},
125
+ type: 'and',
126
+ useListViewType: true,
127
+ browserTreeDefaultExpandedLevel: '0',
128
+ current: pageNo,
129
+ pageSize,
130
+ quickSearchDatas: { name },
131
+ };
132
+ const response = await env.host.request({
133
+ method: 'POST',
134
+ path: '/api/doc/common/browser/data/virtualFolder',
135
+ body,
136
+ operation: action,
137
+ });
138
+ const items = nestedList(response, 'data', 'data');
139
+ const folders = [];
140
+ for (const entry of items) {
141
+ if (!isRecord(entry))
142
+ continue;
143
+ const content = typeof entry.content === 'string' ? entry.content : String(entry.content ?? '');
144
+ const matched = VIRTUAL_CONTENT_RE.exec(content);
145
+ folders.push({
146
+ id: String(entry.id ?? ''),
147
+ name: matched ? matched[1] : content,
148
+ path: matched ? matched[2] : '',
149
+ parent_folder_id: entry.parentFolderId ?? '',
150
+ });
151
+ }
152
+ return caizhilianSuccess(action, {
153
+ page_no: pageNo,
154
+ page_size: pageSize,
155
+ has_next: items.length >= pageSize,
156
+ folders,
157
+ });
158
+ }
159
+ function browserSearch(config) {
160
+ return async (args, env) => {
161
+ const { pageNo, pageSize } = parsePage(args, 50);
162
+ const quickSearchDatas = {};
163
+ const keyword = optionalText(args.keyword, 'keyword');
164
+ if (keyword)
165
+ quickSearchDatas[config.quickKey] = keyword;
166
+ const body = {
167
+ ...config.head,
168
+ current: pageNo,
169
+ pageSize,
170
+ formDatas: {},
171
+ quickSearchDatas,
172
+ type: 'and',
173
+ ...(config.tail ?? {}),
174
+ };
175
+ const response = await env.host.request({
176
+ method: 'POST',
177
+ path: config.path,
178
+ body,
179
+ operation: config.action,
180
+ });
181
+ const items = nestedList(response, 'data', 'data');
182
+ return caizhilianSuccess(config.action, {
183
+ page_no: pageNo,
184
+ page_size: pageSize,
185
+ has_next: hasNextPage(items, pageSize),
186
+ [config.resultKey]: items.filter(isRecord).map(config.mapItem),
187
+ });
188
+ };
189
+ }
190
+ const idName = (item) => ({ id: String(item.id ?? ''), name: item.name ?? '' });
191
+ const userSearch = browserSearch({
192
+ action: 'caizhilian.org.search-user',
193
+ path: '/api/hrm/common/browser/data/resource',
194
+ quickKey: 'username',
195
+ resultKey: 'users',
196
+ head: {
197
+ browserMultiple: true,
198
+ authWecahtBook: true,
199
+ wxDepNeedConvertCount: 0,
200
+ wxEmpNeedConvertCount: 0,
201
+ wxTotalNeedConvertCount: 0,
202
+ cmd: 'all',
203
+ },
204
+ tail: { containsNoneAccount: false, containsPartTimeEmployee: false },
205
+ mapItem: (item) => ({ id: item.id ?? '', name: item.name ?? '', department: item.department ?? '' }),
206
+ });
207
+ const departmentSearch = browserSearch({
208
+ action: 'caizhilian.org.search-department',
209
+ path: '/api/hrm/common/browser/data/department',
210
+ quickKey: 'name',
211
+ resultKey: 'departments',
212
+ head: { browserMultiple: true, virtualType: 'ALL', cmd: 'list' },
213
+ tail: { stopDepartment: false, enableSubcompany: false },
214
+ mapItem: (item) => ({
215
+ id: String(item.id ?? ''),
216
+ name: item.name ?? '',
217
+ sup_department: item.supDepartment ?? '',
218
+ parent_id: String(item.parent ?? ''),
219
+ has_sub: Boolean(item.hasSub ?? false),
220
+ }),
221
+ });
222
+ const subcompanySearch = browserSearch({
223
+ action: 'caizhilian.org.search-subcompany',
224
+ path: '/api/hrm/common/browser/data/subcompany',
225
+ quickKey: 'name',
226
+ resultKey: 'subcompanies',
227
+ head: { browserMultiple: true, virtualType: 'ALL', cmd: 'list' },
228
+ tail: { stopDepartment: false },
229
+ mapItem: (item) => ({
230
+ id: String(item.id ?? ''),
231
+ name: item.name ?? '',
232
+ parent_id: String(item.parent ?? ''),
233
+ sup_department: item.supSubDepartment ?? '',
234
+ }),
235
+ });
236
+ const externalSearch = browserSearch({
237
+ action: 'caizhilian.org.search-external',
238
+ path: '/api/hrm/common/browser/data/external',
239
+ quickKey: 'name',
240
+ resultKey: 'externals',
241
+ head: { browserMultiple: true, cmd: 'list' },
242
+ mapItem: idName,
243
+ });
244
+ const positionSearch = browserSearch({
245
+ action: 'caizhilian.org.search-position',
246
+ path: '/api/hrm/common/browser/data/position',
247
+ quickKey: 'name',
248
+ resultKey: 'positions',
249
+ head: { browserMultiple: true, cmd: 'list' },
250
+ mapItem: (item) => ({ id: String(item.id ?? ''), name: item.name ?? '', code: item.code ?? '' }),
251
+ });
252
+ const roleSearch = browserSearch({
253
+ action: 'caizhilian.org.search-role',
254
+ path: '/api/hrm/common/browser/data/role',
255
+ quickKey: 'role_name',
256
+ resultKey: 'roles',
257
+ head: { browserMultiple: true },
258
+ mapItem: idName,
259
+ });
260
+ const customerSearch = browserSearch({
261
+ action: 'caizhilian.org.search-customer',
262
+ path: '/api/crm/common/browser/data/customer',
263
+ quickKey: 'customer_name',
264
+ resultKey: 'customers',
265
+ head: { browserMultiple: true },
266
+ mapItem: idName,
267
+ });
268
+ const customerTypeSearch = browserSearch({
269
+ action: 'caizhilian.org.search-customer-type',
270
+ path: '/api/crm/common/browser/data/dictionary',
271
+ quickKey: 'name',
272
+ resultKey: 'customer_types',
273
+ head: { browserMultiple: false, propertyType: 'customerType' },
274
+ mapItem: idName,
275
+ });
276
+ // ── caizhilian.compare.search-documents ───────────────────
277
+ async function searchCompareDocuments(args, env) {
278
+ const action = 'caizhilian.compare.search-documents';
279
+ const { pageNo, pageSize } = parsePage(args, 20);
280
+ const rawName = args.name === undefined || args.name === null ? '' : String(args.name);
281
+ const nameClean = rawName.trim();
282
+ const body = {
283
+ pageNo,
284
+ pageSize,
285
+ keywords: nameClean ? rawName : '',
286
+ };
287
+ const conditions = [];
288
+ if (nameClean)
289
+ conditions.push({ id: 'name', type: 'string', value: rawName });
290
+ const author = optionalText(args.author, 'author');
291
+ if (author)
292
+ conditions.push({ id: 'author', operate: 'eq', type: 'array', value: author });
293
+ const creator = optionalText(args.creator, 'creator');
294
+ if (creator)
295
+ conditions.push({ id: 'creator', operate: 'eq', type: 'array', value: creator });
296
+ const createTime = timeCondition(args);
297
+ if (createTime)
298
+ conditions.push(createTime);
299
+ const folder = optionalText(args.folder, 'folder');
300
+ if (folder)
301
+ conditions.push({ id: 'folder', operate: 'eq', type: 'folder', value: folder });
302
+ body.conditions = conditions;
303
+ const response = await env.host.request({ method: 'POST', path: '/api/doc/documents/list', body, operation: action });
304
+ return documentPage(action, response, pageNo, pageSize);
305
+ }
306
+ export const caizhilianSearchHandlers = {
307
+ 'caizhilian.document.search': { execute: searchDocuments },
308
+ 'caizhilian.folder.search-virtual': { execute: searchVirtualFolders },
309
+ 'caizhilian.org.search-user': { execute: userSearch },
310
+ 'caizhilian.org.search-department': { execute: departmentSearch },
311
+ 'caizhilian.org.search-subcompany': { execute: subcompanySearch },
312
+ 'caizhilian.org.search-external': { execute: externalSearch },
313
+ 'caizhilian.org.search-position': { execute: positionSearch },
314
+ 'caizhilian.org.search-role': { execute: roleSearch },
315
+ 'caizhilian.org.search-customer': { execute: customerSearch },
316
+ 'caizhilian.org.search-customer-type': { execute: customerTypeSearch },
317
+ 'caizhilian.compare.search-documents': { execute: searchCompareDocuments },
318
+ };
@@ -0,0 +1,294 @@
1
+ /**
2
+ * caizhilian.setting-attach — 附件设置(文件设置 → 附件设置)
3
+ *
4
+ * 覆盖「文件设置 → 附件设置」页面的 11 项配置:
5
+ * - 上传最大、上传分片大小、格式控制方式、格式列表
6
+ * - 非图片/音视频打开方式、图片/音视频打开方式
7
+ * - 预览显示附件列表、附件列默认展开、附件附加提示
8
+ * - 附件批量下载、禁止移动端下载
9
+ *
10
+ * 接口:
11
+ * - 拉全量:POST /api/file/tenant/setting
12
+ * - 保存:POST /api/file/tenant/setting/save(只 POST 改了的字段)
13
+ */
14
+ import { CaizhilianCliError, caizhilianValidationError } from '../../errors.js';
15
+ import { issueWriteLease } from '../confirm.js';
16
+ import { caizhilianSuccess } from '../types.js';
17
+ const ACTION = 'caizhilian.setting-attach';
18
+ // ── 接口路径 ──────────────────────────────────────────────
19
+ const GET_PATH = '/api/file/tenant/setting';
20
+ const SAVE_PATH = '/api/file/tenant/setting/save';
21
+ // ── 字段映射(CLI key → DTO 字段) ─────────────────────────
22
+ const FIELD_MAP = {
23
+ 'upload-max': { dtoKey: 'sysMaxSingleUploadSize', type: 'string' },
24
+ 'shard-size': { dtoKey: 'uploadShardSize', type: 'number', parse: (v) => parseInt(v, 10) },
25
+ 'format-mode': { dtoKey: 'sysFormatWhitesEnable', type: 'boolean', parse: (v) => v === 'whitelist' || v === '白名单' },
26
+ 'format-list': { dtoKey: 'sysFormatWhites', type: 'string' }, // 实际写入位置取决于 mode
27
+ 'non-image-open': { dtoKey: 'sysNonImageMediaOpenType', type: 'string' },
28
+ 'image-open': { dtoKey: 'sysImageMediaOpenType', type: 'string' },
29
+ 'show-attach-list': { dtoKey: 'sysPreviewShowAttachmentList', type: 'boolean' },
30
+ 'attach-expand': { dtoKey: 'sysAttachmentListDefaultExpand', type: 'boolean' },
31
+ 'custom-msg': { dtoKey: 'sysUploadCustomMsgEnable', type: 'boolean' },
32
+ 'batch-download': { dtoKey: 'sysBatchDownload', type: 'boolean' },
33
+ 'mobile-block': { dtoKey: 'sysAppDownload', type: 'boolean', parse: (v) => !parseBoolean(v) }, // 语义取反
34
+ 'download-pdf-types': { dtoKey: 'sysDownloadToPdfFileTypes', type: 'string' },
35
+ 'img-compress': { dtoKey: 'sysImgCompressEnable', type: 'boolean' },
36
+ 'img-compress-quality': { dtoKey: 'sysImgCompressQuality', type: 'string' },
37
+ 'auto-clear-version': { dtoKey: 'sysAutoClearFileVersion', type: 'boolean' },
38
+ 'version-size': { dtoKey: 'sysFileVersionSize', type: 'number', parse: (v) => parseInt(v, 10) },
39
+ 'version-time': { dtoKey: 'sysFileVersionTime', type: 'number', parse: (v) => parseInt(v, 10) },
40
+ 'print-pdf-types': { dtoKey: 'sysPrintToPdfFileTypes', type: 'string' },
41
+ 'version-clean-type': { dtoKey: 'sysAutoClearFileVersionType', type: 'string' },
42
+ 'version-size-type': { dtoKey: 'sysFileVersionSizeType', type: 'string' },
43
+ 'version-time-type': { dtoKey: 'sysFileVersionTimeType', type: 'string' },
44
+ };
45
+ // ── 辅助函数 ──────────────────────────────────────────────
46
+ function asRecord(value) {
47
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
48
+ }
49
+ function isPlainObject(value) {
50
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
51
+ }
52
+ function parseBoolean(value) {
53
+ if (typeof value === 'boolean')
54
+ return value;
55
+ const s = String(value).toLowerCase();
56
+ return ['true', '1', '开', '启用'].includes(s);
57
+ }
58
+ function pyRepr(value) {
59
+ return JSON.stringify(value);
60
+ }
61
+ function sortedJoin(set) {
62
+ return [...set].sort().join(', ');
63
+ }
64
+ // ── 读取设置 ──────────────────────────────────────────────
65
+ async function getSettingAttach(args, env) {
66
+ const response = await env.host.request({
67
+ method: 'POST',
68
+ path: GET_PATH,
69
+ body: {},
70
+ operation: ACTION,
71
+ });
72
+ const data = asRecord(response);
73
+ if (!data.status && !data.success) {
74
+ throw new CaizhilianCliError('api', 'business_error', String(data.msg || data.message || '读取附件设置失败'), {
75
+ code: data.code ?? data.status,
76
+ details: { action: ACTION, message: String(data.msg || data.message || '读取附件设置失败') },
77
+ exitCode: 1,
78
+ });
79
+ }
80
+ const settings = asRecord(data.data);
81
+ return caizhilianSuccess(ACTION, {
82
+ settings: {
83
+ upload_max: settings.sysMaxSingleUploadSize || '',
84
+ upload_max_limit: settings.sysMaxSingleUploadLimitSize || '',
85
+ shard_size: settings.uploadShardSize || 0,
86
+ format_mode: settings.sysFormatWhitesEnable ? 'whitelist' : 'blacklist',
87
+ format_list: settings.sysFormatWhitesEnable ? (settings.sysFormatWhites || '*') : (settings.sysFormatBlacks || ''),
88
+ non_image_open: settings.sysNonImageMediaOpenType || 'newTab',
89
+ image_open: settings.sysImageMediaOpenType || 'previewComponent',
90
+ show_attach_list: settings.sysPreviewShowAttachmentList ?? true,
91
+ attach_expand: settings.sysAttachmentListDefaultExpand ?? true,
92
+ custom_msg_enable: settings.sysUploadCustomMsgEnable ?? false,
93
+ custom_msg: settings.sysUploadCustomMsg || '',
94
+ batch_download: settings.sysBatchDownload ?? true,
95
+ mobile_block: !(settings.sysAppDownload ?? true), // 语义取反
96
+ download_pdf_types: settings.sysDownloadToPdfFileTypes || '',
97
+ img_compress: settings.sysImgCompressEnable ?? false,
98
+ img_compress_quality: settings.sysImgCompressQuality || 'medium',
99
+ auto_clear_version: settings.sysAutoClearFileVersion ?? false,
100
+ version_size: settings.sysFileVersionSize ?? -1,
101
+ version_time: settings.sysFileVersionTime ?? -1,
102
+ print_pdf_types: settings.sysPrintToPdfFileTypes || '',
103
+ version_clean_type: settings.sysAutoClearFileVersionType || 'versionSize',
104
+ version_size_type: settings.sysFileVersionSizeType || 'selected',
105
+ version_time_type: settings.sysFileVersionTimeType || 'selected',
106
+ },
107
+ });
108
+ }
109
+ // ── 保存设置(prepare/apply)──────────────────────────────────────
110
+ function buildChangedBody(items, current) {
111
+ const changed = {};
112
+ for (const [key, value] of Object.entries(items)) {
113
+ const field = FIELD_MAP[key];
114
+ if (!field) {
115
+ throw caizhilianValidationError('unknown_field', `未知字段: ${key}`);
116
+ }
117
+ let parsed;
118
+ if (field.parse) {
119
+ parsed = field.parse(String(value));
120
+ }
121
+ else if (field.type === 'boolean') {
122
+ parsed = parseBoolean(value);
123
+ }
124
+ else if (field.type === 'number') {
125
+ parsed = parseInt(String(value), 10);
126
+ if (isNaN(parsed)) {
127
+ throw caizhilianValidationError('number_invalid', `${key} 必须是数字`);
128
+ }
129
+ }
130
+ else {
131
+ parsed = String(value);
132
+ }
133
+ // 特殊处理:format-list 根据 mode 写入不同字段
134
+ if (key === 'format-list') {
135
+ const mode = items['format-mode'] !== undefined
136
+ ? (items['format-mode'] === 'whitelist' || items['format-mode'] === '白名单')
137
+ : current.sysFormatWhitesEnable;
138
+ if (mode) {
139
+ changed['sysFormatWhites'] = parsed;
140
+ }
141
+ else {
142
+ changed['sysFormatBlacks'] = parsed;
143
+ }
144
+ }
145
+ else if (key === 'custom-msg') {
146
+ // custom-msg 复合字段:bool + text
147
+ const enable = parseBoolean(value);
148
+ changed['sysUploadCustomMsgEnable'] = enable;
149
+ if (typeof value === 'string' && value.includes('::')) {
150
+ const text = value.split('::').slice(1).join('::');
151
+ changed['sysUploadCustomMsg'] = text;
152
+ }
153
+ }
154
+ else {
155
+ changed[field.dtoKey] = parsed;
156
+ }
157
+ }
158
+ return changed;
159
+ }
160
+ async function setSettingAttachPrepare(args, env) {
161
+ const items = args.items;
162
+ if (!isPlainObject(items)) {
163
+ throw caizhilianValidationError('input_not_object', 'items 必须是对象');
164
+ }
165
+ // 读取当前设置
166
+ const currentResponse = await env.host.request({
167
+ method: 'POST',
168
+ path: GET_PATH,
169
+ body: {},
170
+ operation: ACTION,
171
+ });
172
+ const currentData = asRecord(currentResponse);
173
+ if (!currentData.status && !currentData.success) {
174
+ throw new CaizhilianCliError('api', 'business_error', String(currentData.msg || currentData.message || '读取附件设置失败'), {
175
+ code: currentData.code ?? currentData.status,
176
+ details: { action: ACTION, message: String(currentData.msg || currentData.message || '读取附件设置失败') },
177
+ exitCode: 1,
178
+ });
179
+ }
180
+ const current = asRecord(currentData.data);
181
+ // 构建改动
182
+ const changed = buildChangedBody(items, current);
183
+ // 签发 continuation(含环境指纹,防跨账号复用)
184
+ const lease = await issueWriteLease(env, 'caizhilian.setting-attach.set.apply', args, { changed, items });
185
+ return caizhilianSuccess('caizhilian.setting-attach.set.prepare', {
186
+ changed,
187
+ current: {
188
+ upload_max: current.sysMaxSingleUploadSize || '',
189
+ format_mode: current.sysFormatWhitesEnable ? 'whitelist' : 'blacklist',
190
+ format_list: current.sysFormatWhitesEnable ? (current.sysFormatWhites || '*') : (current.sysFormatBlacks || ''),
191
+ batch_download: current.sysBatchDownload ?? true,
192
+ mobile_block: !(current.sysAppDownload ?? true),
193
+ },
194
+ continuation: lease.continuation,
195
+ expires_in_ms: lease.expiresInMs,
196
+ });
197
+ }
198
+ async function setSettingAttachApply(args, env, lease) {
199
+ // 使用 lease 中的 changed
200
+ const changed = lease.changed;
201
+ if (!changed || Object.keys(changed).length === 0) {
202
+ throw caizhilianValidationError('continuation_invalid', 'continuation 中无改动');
203
+ }
204
+ // 保存
205
+ const saveResponse = await env.host.request({
206
+ method: 'POST',
207
+ path: SAVE_PATH,
208
+ body: changed,
209
+ operation: 'caizhilian.setting-attach.set.apply',
210
+ });
211
+ const saveData = asRecord(saveResponse);
212
+ if (!saveData.status && !saveData.success) {
213
+ throw new CaizhilianCliError('api', 'business_error', String(saveData.msg || saveData.message || '保存附件设置失败'), {
214
+ code: saveData.code ?? saveData.status,
215
+ details: { action: 'caizhilian.setting-attach.set.apply', message: String(saveData.msg || saveData.message || '保存附件设置失败') },
216
+ exitCode: 1,
217
+ });
218
+ }
219
+ // 回读复核
220
+ const verifyResponse = await env.host.request({
221
+ method: 'POST',
222
+ path: GET_PATH,
223
+ body: {},
224
+ operation: 'caizhilian.setting-attach.set.apply',
225
+ });
226
+ const verifyData = asRecord(verifyResponse);
227
+ const verified = asRecord(verifyData.data);
228
+ return caizhilianSuccess('caizhilian.setting-attach.set.apply', {
229
+ changed,
230
+ verified: {
231
+ upload_max: verified.sysMaxSingleUploadSize || '',
232
+ format_mode: verified.sysFormatWhitesEnable ? 'whitelist' : 'blacklist',
233
+ format_list: verified.sysFormatWhitesEnable ? (verified.sysFormatWhites || '*') : (verified.sysFormatBlacks || ''),
234
+ batch_download: verified.sysBatchDownload ?? true,
235
+ mobile_block: !(verified.sysAppDownload ?? true),
236
+ },
237
+ });
238
+ }
239
+ // ── 通过文件夹反查审批流程 ──────────────────────────────────────────
240
+ async function listWorkflowsByFolders(args, env) {
241
+ const action = 'caizhilian.setting-attach.list-workflows-by-folders';
242
+ const folderIds = args.folder_ids;
243
+ if (!Array.isArray(folderIds) || folderIds.length === 0) {
244
+ throw caizhilianValidationError('folder_ids_required', 'folder_ids 必须是非空数组');
245
+ }
246
+ const response = await env.host.request({
247
+ method: 'POST',
248
+ path: '/api/doc/approvalWorkflow/listWorkflowByFolders',
249
+ body: { folderIds },
250
+ operation: action,
251
+ tolerateBusinessError: true,
252
+ });
253
+ const data = asRecord(response);
254
+ // 检查接口是否不存在(404 等)
255
+ if (data.code === 404 || data.status === 404) {
256
+ throw new CaizhilianCliError('api', 'feature_not_supported', '当前环境暂不支持该功能', {
257
+ code: 404,
258
+ details: {
259
+ action,
260
+ message: '当前环境暂不支持通过文件夹反查审批流程的功能',
261
+ },
262
+ exitCode: 1,
263
+ });
264
+ }
265
+ // 检查业务成功
266
+ if (!data.status && !data.success && data.code !== 200) {
267
+ throw new CaizhilianCliError('api', 'business_error', String(data.msg || data.message || '查询失败'), {
268
+ code: data.code ?? data.status,
269
+ details: { action, message: String(data.msg || data.message || '查询失败') },
270
+ exitCode: 1,
271
+ });
272
+ }
273
+ const workflows = Array.isArray(data.data) ? data.data : [];
274
+ return caizhilianSuccess(action, {
275
+ folder_ids: folderIds,
276
+ workflows: workflows.map((item) => ({
277
+ workflow_id: item.workflowId || '',
278
+ workflow_name: item.workflowName || '',
279
+ type_id: item.typeId || '',
280
+ type_name: item.typeName || '',
281
+ })),
282
+ total: workflows.length,
283
+ });
284
+ }
285
+ // ── 处理器汇总 ────────────────────────────────────────────
286
+ export const caizhilianSettingAttachHandlers = {
287
+ 'caizhilian.setting-attach.get': { execute: getSettingAttach },
288
+ 'caizhilian.setting-attach.list-workflows-by-folders': { execute: listWorkflowsByFolders },
289
+ 'caizhilian.setting-attach.set': {
290
+ prepare: setSettingAttachPrepare,
291
+ apply: setSettingAttachApply,
292
+ targetKeys: ['items'],
293
+ },
294
+ };