kcode-pi 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +358 -0
- package/dist/cli/kcode.d.ts +15 -0
- package/dist/cli/kcode.js +153 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +7 -0
- package/docs/KCODE_DISTRIBUTION.md +91 -0
- package/extensions/kingdee-harness.ts +180 -0
- package/extensions/kingdee-header.ts +122 -0
- package/extensions/kingdee-tools.ts +379 -0
- package/knowledge/.backup/v1.0.0/version.json +10 -0
- package/knowledge/cangqiong/product-notes.md +15 -0
- package/knowledge/common/business-flows.md +115 -0
- package/knowledge/common/config-guides.md +110 -0
- package/knowledge/common/error-patterns.md +170 -0
- package/knowledge/common/implementation.md +144 -0
- package/knowledge/cosmic/hard-constraints.md +38 -0
- package/knowledge/cosmic/ksql-datafix.md +34 -0
- package/knowledge/cosmic/platform-baseline.md +32 -0
- package/knowledge/cosmic/plugin-decision-matrix.md +40 -0
- package/knowledge/cosmic/review-checklist.md +40 -0
- package/knowledge/cosmic/unittest.md +35 -0
- package/knowledge/enterprise/api-reference.md +186 -0
- package/knowledge/enterprise/code-patterns.md +217 -0
- package/knowledge/enterprise/plugin-lifecycle.md +188 -0
- package/knowledge/enterprise/tables.json +159 -0
- package/knowledge/flagship/api-reference.md +237 -0
- package/knowledge/flagship/code-patterns.md +246 -0
- package/knowledge/flagship/cosmic-platform-note.md +15 -0
- package/knowledge/flagship/plugin-lifecycle.md +248 -0
- package/knowledge/flagship/tables.json +159 -0
- package/knowledge/version.json +10 -0
- package/knowledge/xinghan/product-notes.md +15 -0
- package/package.json +71 -0
- package/prompts/kd-discuss.md +11 -0
- package/prompts/kd-execute.md +12 -0
- package/prompts/kd-plan.md +12 -0
- package/prompts/kd-ship.md +12 -0
- package/prompts/kd-spec.md +12 -0
- package/prompts/kd-verify.md +12 -0
- package/skills/kd-check/SKILL.md +26 -0
- package/skills/kd-cosmic-dev/SKILL.md +82 -0
- package/skills/kd-cosmic-review/SKILL.md +90 -0
- package/skills/kd-cosmic-unittest/SKILL.md +92 -0
- package/skills/kd-debug/SKILL.md +30 -0
- package/skills/kd-discuss/SKILL.md +24 -0
- package/skills/kd-execute/SKILL.md +22 -0
- package/skills/kd-gen/SKILL.md +34 -0
- package/skills/kd-ksql/SKILL.md +86 -0
- package/skills/kd-plan/SKILL.md +24 -0
- package/skills/kd-ship/SKILL.md +22 -0
- package/skills/kd-spec/SKILL.md +24 -0
- package/skills/kd-verify/SKILL.md +22 -0
- package/themes/kcode-dark.json +81 -0
- package/vendor/kingdee-skills/cosmic-unittest/SKILL.md +788 -0
- package/vendor/kingdee-skills/cosmic-unittest/author-cache.json +5 -0
- package/vendor/kingdee-skills/cosmic-unittest/cosmic-unittest-skill-overview.html +746 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/business-test.md +205 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/common-test.md +257 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/formplugin-test.md +560 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/op-plugin-test.md +231 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/validator-test.md +232 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/business-helper.md +184 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/common-module.md +355 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/convert-plugin.md +130 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/formplugin.md +235 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/op-plugin.md +226 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/validator.md +206 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/SKILL.md +674 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/advanced-scenario-checklist.md +307 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/algox-performance-checklist.md +129 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/coding-standard-checklist.md +491 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/cosmic-api-checklist.md +285 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/data-access-checklist.md +261 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/data-transaction-checklist.md +390 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/domain-logic-checklist.md +295 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/form-plugin-checklist.md +508 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/infra-checklist.md +254 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/ksql-checklist.md +305 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/lifecycle-checklist.md +298 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/operation-plugin-checklist.md +442 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/test-mock-checklist.md +120 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/ui-performance-checklist.md +320 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/pattern-matcher.py +336 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/review-score-calculator.py +121 -0
- package/vendor/kingdee-skills/ok-cosmic/CHANGELOG.md +295 -0
- package/vendor/kingdee-skills/ok-cosmic/README.md +460 -0
- package/vendor/kingdee-skills/ok-cosmic/SKILL.md +287 -0
- package/vendor/kingdee-skills/ok-cosmic/agents/openai.yaml +17 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/BatchImportPluginTemplate.java +93 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/BillPlugInTemplate.java +156 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ConvertPlugInTemplate.java +255 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/FormPluginTemplate.java +597 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/IWorkflowPluginTemplate.java +91 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ListPluginTemplate.java +194 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/OpPluginTemplate.java +201 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/OpenApiControllerTemplate.java +103 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/PrintPluginTemplate.java +95 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ReportFormPluginTemplate.java +257 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ReportListDataPluginTemplate.java +70 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/StandardTreeListPluginTemplate.java +130 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/TaskTemplate.java +80 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/TreeListPluginTemplate.java +152 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/WriteBackPlugInTemplate.java +286 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/attachment/AttachmentUploadBindSample.java +93 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/botp/BotpTracePushSample.java +168 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/botp/SampleConvertPlugin.java +223 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/cache/SampleCacheUsage.java +218 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/concurrent/SampleThreadPoolBatch.java +156 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/data/DynamicObjectCrudSample.java +205 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/data/DynamicObjectOpsSample.java +100 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/BeforeOperationConfirmSample.java +217 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ConfirmDialogSample.java +131 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/EntryRowCalculateSample.java +116 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/F7FilterSample.java +134 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/GetAndSetValueSample.java +176 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/HyperlinkJumpSample.java +124 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/OpenBillModalSample.java +253 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ReturnParentDataSample.java +295 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/TreeControlSample.java +140 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ViewControlOpsSample.java +132 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/list/ListPluginBasicSample.java +170 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/list/ListPreOpenFilterSample.java +68 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/message/MessageNotifySample.java +95 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/mq/SampleMQConsumer.java +198 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/mq/sample_mq.xml +15 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/operation/OpAddValidatorsSample.java +137 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/operation/OperationOptionBridgeSample.java +228 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/package-info.java +19 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/BaseDataQuerySample.java +194 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/BatchQuerySample.java +368 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/DataSetQueryStatSample.java +131 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportFormPlugin.java +179 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportListDataPlugin.java +616 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/snippets-guide.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/task/ScheduleTaskSample.java +160 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/workflow/SampleWorkflowPlugin.java +302 -0
- package/vendor/kingdee-skills/ok-cosmic/manifest.json +78 -0
- package/vendor/kingdee-skills/ok-cosmic/ok-cosmic-intro.html +903 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/attachment-api.md +114 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/botp-convert.md +98 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/dynamic-object.md +113 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/entity-metadata.md +123 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/event-lifecycle.md +184 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/flex-prop.md +114 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/form-utils.md +133 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/operate-chain.md +159 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/plugin-base.md +218 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/query-dataset.md +149 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/request-context.md +88 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/view-handler.md +157 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-bill.md +76 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-botp.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-form.md +165 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-import.md +69 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-list.md +227 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-openapi.md +112 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-operation.md +135 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-print.md +65 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-report-data.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-report-form.md +90 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-task.md +62 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-tree-list.md +71 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-workflow.md +82 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-writeback.md +71 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-algo.md +67 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-cache.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-dynamic-model-svc.md +82 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-dynamic-object.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-entity-model.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-exception.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-file.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-id.md +47 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-lock.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-log.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-network-control.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-orm-access.md +78 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-request-context.md +62 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-threadpool.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-tx.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-utils.md +67 -0
- package/vendor/kingdee-skills/ok-cosmic/requirements.txt +2 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/a-layer-rules.json +24 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/anti-patterns.md +48 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/cheat-sheet.md +256 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/coding-preferences.md +140 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/constraints.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/decision-matrix.md +222 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/intent-routing.md +94 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/platform-baseline.md +69 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/post-check.md +109 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/config_loader.py +204 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-api-knowledge.py +910 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-basedata-query.py +359 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-config-check.py +181 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-extpoints-query.py +389 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-form-metadata.py +856 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-check.py +262 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-lint.py +293 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/__init__.py +2 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/base.py +393 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/resource_check.py +176 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/scene_check.py +375 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/style_check.py +434 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/verify_check.py +36 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/route_client.py +186 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/script_utils.py +40 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/sqlite_cache.py +142 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-commons.jar +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-features.jar +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/ok-cosmic-docs.db +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/ok-cosmic.json +13 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup-mac.sh +18 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup-windows.bat +53 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup.jar +0 -0
- package/vendor/kingdee-skills/ok-ksql/SKILL.md +81 -0
- package/vendor/kingdee-skills/ok-ksql/agents/openai.yaml +7 -0
- package/vendor/kingdee-skills/ok-ksql/manifest.json +14 -0
- package/vendor/kingdee-skills/ok-ksql/references/ksql-datafix.md +452 -0
- package/vendor/kingdee-skills/ok-ksql/scripts/ksql_lint.py +363 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# 附件与文件系统工具 (AttachmentUtils)
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
- 适用:附件面板复制、附件 DTO 绑定、跨单据附件同步和签名 URL 处理。
|
|
5
|
+
- 先抓:优先用 `AttachmentUtils` 处理复制、绑定、下载与 URL 判定,少直接拼底层服务。
|
|
6
|
+
- 跳转:纯文件流上传下载且不挂业务附件面板时,改读 `base/sdk/sdk-file.md`。
|
|
7
|
+
- 继续读全文:当你要确认 `CopyFeature` 选项、面板绑定细节或跨单据同步示例时。
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
苍穹的附件系统涉及物理文件、URL 签名与业务面板绑定。`AttachmentUtils` (位于 `kd.cd.common.attachment`) 旨在简化跨单据附件同步、文件在线下载以及附件面板的全方位管理。本规范支持所有涉及文件流的操作场景。
|
|
11
|
+
|
|
12
|
+
> **适用边界**
|
|
13
|
+
> ✅ 适用:附件上传/下载/复制/同步/面板绑定。
|
|
14
|
+
> ❌ 不适用:纯文件流操作(无业务面板)请直接用 SDK `FileServiceHelper`。
|
|
15
|
+
|
|
16
|
+
## 核心类
|
|
17
|
+
- **`kd.cd.common.attachment.AttachmentUtils`**: **附件处理核心工具类**。
|
|
18
|
+
- **`kd.bos.servicehelper.AttachmentServiceHelper`**: 原生附件服务帮助类。
|
|
19
|
+
- **`kd.bos.servicehelper.AttDto`**: 附件数据传输对象。
|
|
20
|
+
- **`kd.cd.common.attachment.CopyFeature`**: 附件复制选项配置。
|
|
21
|
+
- **`kd.cd.common.attachment.BindType`**: 绑定类型枚举。
|
|
22
|
+
|
|
23
|
+
## 常用 API 方法
|
|
24
|
+
|
|
25
|
+
### 1. 附件面板复制与绑定
|
|
26
|
+
- `copyToPanel(String srcFormId, Object srcPk, String srcPanel, String tarFormId, Object tarPk, String tarPanel)`: **最常用**。实现附件面板的全量文件复制。
|
|
27
|
+
- `copyToPanel(String srcFormId, Object srcPk, String srcPanel, String tarFormId, Object tarPk, String tarPanel, CopyFeature feature)`: 带复制选项的附件面板复制。
|
|
28
|
+
- `copyToPanel(Collection<Long> attPks, String tarFormId, Object tarPk, String tarPanel)`: 根据附件主键集复制。
|
|
29
|
+
- `copyToPanel(Collection<Long> attPks, String tarFormId, Object tarPk, String tarPanel, CopyFeature feature)`: 根据附件主键集复制,带复制选项。
|
|
30
|
+
- `bind(String entityId, Object pkValue, List<AttDto> attDtos)`: 将上传的文件正式绑定到具体单据主键(转正)。
|
|
31
|
+
- `bindSingle(String entityId, Object pkValue, AttDto attDto)`: 绑定单个文件。
|
|
32
|
+
|
|
33
|
+
### 2. 文件解析与操作
|
|
34
|
+
- `download(String pathOrUrl)`: 将 URL 下载并转换为 `InputStream` 流。**调用方必须负责关闭返回的 InputStream**。
|
|
35
|
+
- `physicDelete(String... pathOrUrls)`: 物理删除文件(兼容文件服务器或文件缓存删除)。
|
|
36
|
+
- `getFileName(String path)`: 获取文件名。
|
|
37
|
+
- `getSuffix(String str)`: 获取后缀。
|
|
38
|
+
- `isValidPath(String path)`: 判定是否为有效路径。
|
|
39
|
+
|
|
40
|
+
### 3. URL 逻辑判定
|
|
41
|
+
- `isDownloadUrl(String path)`: 判定是否为下载链接。
|
|
42
|
+
- `isTempUrl(String path)`: 判定是否为临时存储区链接。
|
|
43
|
+
- `isImageType(String str)`: 判定是否为图片。
|
|
44
|
+
|
|
45
|
+
### 4. 辅助方法
|
|
46
|
+
- `newAttDto(String panelOrField, String path, long size, Object entryRowPk, Consumer<AttDto> consumer)`: 生成附件信息Dto。
|
|
47
|
+
- `stripFromDownloadUrl(String url)`: 从下载URL中提取路径。
|
|
48
|
+
- `stripParameter(String path)`: 去掉下载路径后的查询参数与片段。
|
|
49
|
+
- `decodeUtf8(String path)`: UTF-8解码。
|
|
50
|
+
|
|
51
|
+
## 示例代码
|
|
52
|
+
|
|
53
|
+
### 自动同步订单附件到入库单
|
|
54
|
+
```java
|
|
55
|
+
package kd.cd.common.demo;
|
|
56
|
+
|
|
57
|
+
import kd.cd.common.attachment.AttachmentUtils;
|
|
58
|
+
|
|
59
|
+
public class AttDemo {
|
|
60
|
+
public void sync(Object orderPk, Object inbillPk) {
|
|
61
|
+
// 1. 同步全量附件面板内容,内部已自动处理物理引用
|
|
62
|
+
AttachmentUtils.copyToPanel(
|
|
63
|
+
"pm_purorderbill", orderPk, "att_panel",
|
|
64
|
+
"stk_purinbill", inbillPk, "att_panel"
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 下载并处理附件
|
|
71
|
+
```java
|
|
72
|
+
public void processAttachment(String fileUrl) {
|
|
73
|
+
// 使用 try-with-resources 确保流关闭
|
|
74
|
+
try (InputStream is = AttachmentUtils.download(fileUrl)) {
|
|
75
|
+
// 处理文件流
|
|
76
|
+
} catch (IOException e) {
|
|
77
|
+
// 异常处理
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 生成并绑定附件Dto
|
|
83
|
+
```java
|
|
84
|
+
public void bindNewAttachment(String entityId, Object pkValue, String path, long size) {
|
|
85
|
+
AttDto attDto = AttachmentUtils.newAttDto("att_panel", path, size, null, dto -> {
|
|
86
|
+
dto.setName("附件名称");
|
|
87
|
+
});
|
|
88
|
+
State result = AttachmentUtils.bindSingle(entityId, pkValue, attDto);
|
|
89
|
+
if (!result.isSuccess()) {
|
|
90
|
+
throw new KDBizException(result.getMessage());
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## CopyFeature 配置选项
|
|
96
|
+
`CopyFeature` 用于控制附件复制时的行为:
|
|
97
|
+
- `setCreatorId(Long)` - 设置创建人ID
|
|
98
|
+
- `setUseCurrentUserAsCreator(boolean)` - 是否使用当前用户作为创建人
|
|
99
|
+
- `setCopyLastModifyTime(boolean)` - 是否复制最后修改时间
|
|
100
|
+
- `setUseCurrentUserAsModifier(boolean)` - 是否使用当前用户作为修改人
|
|
101
|
+
- `setFileSource(Integer)` - 设置文件来源
|
|
102
|
+
- `setClearDesc(boolean)` - 是否清除描述
|
|
103
|
+
|
|
104
|
+
## 实践建议
|
|
105
|
+
1. **优先使用面板复制**: 不要手动解析附件子表获取 URL 拼接。使用 `copyToPanel` 最稳健,且性能最优。
|
|
106
|
+
2. **区分正式区与临时区**: 前端上传的文件位于临时区,如果不调用 `bind` 绑定到单据,系统会在一定时间后自动清理。
|
|
107
|
+
3. **文件名转义**: 处理含中文字符的文件名时,必须确认编码环境,防止出现乱码。
|
|
108
|
+
4. **流关闭**: `download` 方法返回的 InputStream 必须由调用方关闭,建议使用 try-with-resources。
|
|
109
|
+
|
|
110
|
+
## 常见坑位
|
|
111
|
+
1. **物理删除误伤**: `physicDelete` 会立刻销毁物理文件,如果该文件被多个单据引用,可能导致其他单据附件失效。
|
|
112
|
+
2. **下载 URL 超时**: 直接将 `download` 获取的 InputStream 返回前端时,如果流未及时关闭,可能导致连接池溢出。
|
|
113
|
+
3. **附件面板标识错误**: `copyToPanel` 的参数是面板的 **Key**,而非字段 Key,请在设计器属性栏确认。
|
|
114
|
+
4. **流未关闭**: 忘记关闭 `download` 返回的 InputStream 会导致文件句柄泄露或底层连接池耗尽。
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# 单据转换与下推 (BotpUtils & PushResult)
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
- 适用:下推、选单、来源追踪和转换结果处理。
|
|
5
|
+
- 先抓:默认优先 `BotpUtils` / `PushResult`,不要先手写原生转换服务调用。
|
|
6
|
+
- 跳转:只是保存/提交/审核改读 `operate-chain.md`;只是转换插件事件再读 `base/plugin/plugin-botp.md`。
|
|
7
|
+
- 继续读全文:当你要确认上拉、链路追踪或后台自动下推模板时。
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
单据下推(Push)与转换(Convert)是苍穹实现业务流转(如订单下推入库)的核心机制。`BotpUtils` (位于 `kd.cd.common.util`) 对原生的转换服务进行了深度简化,支持一键下推并保存、下推并显示界面、上拉数据以及多层级的正/反向链路追踪。
|
|
11
|
+
|
|
12
|
+
> **适用边界**
|
|
13
|
+
> ✅ 适用:下推/选单/来源追踪/转换结果处理。
|
|
14
|
+
> ❌ 不适用:单纯的操作执行(保存/审核)请用 `OpUtils`;转换插件的事件扩展请用 `ConvertPlugInTemplate`。
|
|
15
|
+
|
|
16
|
+
## 核心类
|
|
17
|
+
- **`kd.cd.common.util.BotpUtils`**: **下推核心工具类**。
|
|
18
|
+
- **`kd.cd.common.util.PushResult`**: 下推结果封装对象,可通过 `getPks()`、`getDatapacks()`、`getSingleDataPack()` 获取结果,并通过 `failThenThrow()` 直接抛出失败详情。
|
|
19
|
+
- **`kd.bos.entity.botp.runtime.ConvertOperationResult`**: 原生转换结果。
|
|
20
|
+
|
|
21
|
+
## 常用 API 方法
|
|
22
|
+
|
|
23
|
+
### 1. 下推操作 (BotpUtils)
|
|
24
|
+
- `pushAndSave(String sourceEntityId, String targetEntityId, Object srcPkValue, String ruleId)`: 一对一后台下推并自动保存的简版重载。
|
|
25
|
+
- `pushAndSave(String sourceEntityId, String targetEntityId, Object srcPkValue, Map<String, List<Long>> entryMapping, String ruleId, Consumer<PushArgs> consumer)`: **最常用**。一对一后台下推并自动保存。
|
|
26
|
+
- `pushNoSave(String sourceEntityId, String targetEntityId, Object srcPkValue, String ruleId)`: 一对一后台下推但不保存的简版重载。
|
|
27
|
+
- `pushNoSave(String sourceEntityId, String targetEntityId, Object srcPkValue, Map<String, List<Long>> entryMapping, String ruleId, Consumer<PushArgs> consumer)`: 下推生成内存对象,不持久化。
|
|
28
|
+
- `push(boolean autoSave, String sourceEntityId, String targetEntityId, List<ListSelectedRow> selectedRows, String ruleId, Consumer<PushArgs> consumer)`: 基于 `selectedRows` 的通用下推入口。
|
|
29
|
+
- `push(boolean autoSave, PushArgs pushArgs)`: 通用下推方法。
|
|
30
|
+
- `pushAndShowTarget(IFormView view, boolean autoSave, String sourceEntityId, String targetEntityId, List<ListSelectedRow> selectedRows, String ruleId, Consumer<PushArgs> consumer)`: 按选择行下推并直接打开目标单。
|
|
31
|
+
- `pushAndShowTarget(IFormView view, boolean autoSave, PushArgs pushArgs)`: 下推并直接在界面弹出目的单。
|
|
32
|
+
|
|
33
|
+
### 2. 上拉操作 (BotpUtils)
|
|
34
|
+
- `drawToBill(IFormView view, String sourceEntityId, Collection<ListSelectedRow> selectRows, String ruleId, Consumer<DrawArgs> consumer)`: 下拉数据至当前单据。
|
|
35
|
+
|
|
36
|
+
### 3. 链路追踪 (BotpUtils)
|
|
37
|
+
- `findAllTargetBills(String targetEntityId, String entityId, Collection<Long> pkValues)`: 正向查找生成的全量目的单,按当前单据主键分组。
|
|
38
|
+
- `findAllTargetBillsFlat(String targetEntityId, String entityId, Collection<Long> pkValues)`: 正向查找,不分组。
|
|
39
|
+
- `findAllSourceBills(String sourceEntityId, String entityId, Collection<Long> pkValues)`: 反向查找来源单据,按当前单据主键分组。
|
|
40
|
+
- `findAllSourceBillsFlat(String sourceEntityId, String entityId, Collection<Long> pkValues)`: 反向查找,不分组。
|
|
41
|
+
- `findDirectTargetBills(String targetEntityId, String entityId, Collection<Long> pkValues)`: 查找直接下游(第一层)。
|
|
42
|
+
- `findDirectSourceBills(String sourceEntityId, String entityId, Collection<Long> pkValues)`: 查找直接上游(第一层)。
|
|
43
|
+
|
|
44
|
+
### 4. 辅助方法
|
|
45
|
+
- `loadTargetEntities(ConvertOperationResult result)`: 从下推结果中加载完整的目的单 DynamicObject。
|
|
46
|
+
- `getConvertFailMsg(ConvertOperationResult result)`: 获取下推失败信息详情。
|
|
47
|
+
- `getDefaultRuleId(String sourceEntityId, String targetEntityId)`: 获取默认转换规则ID(启用状态)。
|
|
48
|
+
- `buildSelectedRows(Map<Object, Map<String, List<Long>>> billData)`: 构建下推选择行信息。
|
|
49
|
+
- `PushResult.failThenThrow()`: 下推失败时直接抛出 `PushConvertFailureException`。
|
|
50
|
+
- `PushResult.getDatapacks()`: 获取目标单数据包;自动保存场景下会懒加载。
|
|
51
|
+
- `PushResult.getSingleDataPack()`: 获取单张目标单数据包。
|
|
52
|
+
|
|
53
|
+
## 示例代码
|
|
54
|
+
|
|
55
|
+
### 后台自动下推模板
|
|
56
|
+
```java
|
|
57
|
+
package kd.cd.common.demo;
|
|
58
|
+
|
|
59
|
+
import kd.cd.common.util.BotpUtils;
|
|
60
|
+
import kd.cd.common.util.PushResult;
|
|
61
|
+
|
|
62
|
+
public class PushDemo {
|
|
63
|
+
public void autoPush(String sourceFormId, String targetFormId, Object sourcePk) {
|
|
64
|
+
// 1. 下推并保存
|
|
65
|
+
PushResult result = BotpUtils.pushAndSave(sourceFormId, targetFormId, sourcePk, null);
|
|
66
|
+
result.failThenThrow();
|
|
67
|
+
|
|
68
|
+
// 2. 获取生成的单据主键
|
|
69
|
+
Object[] targetPks = result.getPks();
|
|
70
|
+
|
|
71
|
+
// 3. 需要时可继续读取完整数据包
|
|
72
|
+
result.getSingleDataPack();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 链路追踪示例
|
|
78
|
+
```java
|
|
79
|
+
public void traceBills(String entityId, Collection<Long> pkValues) {
|
|
80
|
+
// 查询所有下游目标单(按当前单据主键分组)
|
|
81
|
+
Map<Long, Map<String, Set<Long>>> targetBills = BotpUtils.findAllTargetBills(entityId, pkValues);
|
|
82
|
+
|
|
83
|
+
// 查询特定类型的直接上游源单
|
|
84
|
+
Map<Long, Set<Long>> sourceBills = BotpUtils.findDirectSourceBills("pm_purorderbill", entityId, pkValues);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 实践建议
|
|
89
|
+
1. **RuleId 获取**: 建议通过 `BotpUtils.getDefaultRuleId` 获取单据间的默认规则,避免硬编码。
|
|
90
|
+
2. **分录下推**: 使用 `entryMapping` 参数可精确控制需要下推的分录行。
|
|
91
|
+
3. **加载明细**: `loadTargetEntities` 获取的对象包含分录的全量数据。
|
|
92
|
+
4. **链路追踪**: 使用 `findDirectXxx` 方法仅查询直接关联,`findAllXxx` 方法递归查询全量关联。
|
|
93
|
+
|
|
94
|
+
## 常见坑位
|
|
95
|
+
1. **规则未分配**: 如果返回空结果,优先检查"转换规则"是否在目标组织中已发布。
|
|
96
|
+
2. **分录转换缺失**: 如果 RuleId 中未配置分录,下推后的单据将只有表头。
|
|
97
|
+
3. **主键精度丢失**: `Object` 类型的 ID 在跨系统传递时需注意 JS 的数字精度限制(Long -> String)。
|
|
98
|
+
4. **参数顺序**: 注意 pushAndSave/pushNoSave 的参数顺序是 `(sourceEntityId, targetEntityId, ...)` 而非旧版的 `(targetId, ruleId, sourceIds, orgId)`。
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# 动态对象处理全览 (DynamicObject & DynamicObjectUtils)
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
- 适用:`DynamicObject` 安全取值、分录提取、批量扁平化和序列化。
|
|
5
|
+
- 先抓:优先 `DynamicObjectUtils`,避免原生 `get()` + 强转连写导致空指针和类型错误。
|
|
6
|
+
- 跳转:看字段结构/属性元数据改读 `entity-metadata.md`;查询取数改读 `query-dataset.md`。
|
|
7
|
+
- 继续读全文:当你要写深路径取值、批量提取或克隆/状态判断代码时。
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
`DynamicObject` 是苍穹数据的核心载体(内存中的数据包)。`DynamicObjectUtils` (位于 `kd.cd.common.util`) 提供了对这些对象及其集合的高效、安全操作。由于原生 API 容易引发 `NullPointerException` 或类型转换异常,推荐一律使用工具类进行数据存取。
|
|
11
|
+
|
|
12
|
+
> **适用边界**
|
|
13
|
+
> ✅ 适用:DynamicObject 安全取值/批量提取/集合操作。
|
|
14
|
+
> ❌ 不适用:元数据结构解析请用 `entity-metadata.md`;查询构建请用 `query-dataset.md`。
|
|
15
|
+
|
|
16
|
+
## 核心类
|
|
17
|
+
- **`kd.bos.dataentity.entity.DynamicObject`**: 基础数据载体(单对象)。
|
|
18
|
+
- **`kd.bos.dataentity.entity.DynamicObjectCollection`**: 动态对象集合(通常用于表示单据的分录)。
|
|
19
|
+
- **`kd.cd.common.util.DynamicObjectUtils`**: **核心工具类**。
|
|
20
|
+
|
|
21
|
+
## 常用 API 方法
|
|
22
|
+
|
|
23
|
+
### 1. 安全取值与设置 (单对象)
|
|
24
|
+
- `safeGetValue(DynamicObject dyn, String propKey)`: **最常用**。安全获取字段值,字段不存在时返回 null。
|
|
25
|
+
- `safeSetValue(DynamicObject dyn, String propKey, Object value)`: 安全设置值,字段不存在时不抛异常。
|
|
26
|
+
- `nullSafeGet(DynamicObject dyn, String field)`: 空安全获取字段值。
|
|
27
|
+
- `getPkValue(DynamicObject dyn)`: 获取主键。
|
|
28
|
+
- `containsKey(DynamicObject dyn, String key)`: 判断是否包含某字段属性。
|
|
29
|
+
- `containsKey(DynamicObjectCollection coll, String key)`: 判断集合是否包含某字段。
|
|
30
|
+
|
|
31
|
+
### 2. 扁平提取 (深层路径)
|
|
32
|
+
- `flatSetOf(DynamicObject dyn, String expr)`: **深路径提取**。扁平列出动态对象中某字段的所有值,收集为 Set。示例:`"entry.subentry.field"`。
|
|
33
|
+
- `flatListOf(DynamicObject dyn, String expr)`: 同上,返回 List。
|
|
34
|
+
|
|
35
|
+
### 3. 批量属性提取 (集合/分录)
|
|
36
|
+
- `arrayOfIds(DynamicObject[] array)`: 快速提取数组内所有对象的主键 ID。
|
|
37
|
+
- `arrayOfIds(Collection<DynamicObject> coll)`: 快速提取集合内所有对象的主键 ID。
|
|
38
|
+
- `setOfIds(DynamicObject[] array)`: 提取主键 ID,返回 Set。
|
|
39
|
+
- `setOfIds(Collection<DynamicObject> coll)`: 提取主键 ID,返回 Set。
|
|
40
|
+
- `setOf(Collection<DynamicObject> coll, String field)`: 提取并去重某一属性。
|
|
41
|
+
- `listOf(Collection<DynamicObject> coll, String field)`: 提取属性,返回列表。
|
|
42
|
+
- `sumOf(Collection<DynamicObject> coll, String decimalField)`: 对数值字段执行内存汇总。
|
|
43
|
+
|
|
44
|
+
### 4. 数据集转换与序列化
|
|
45
|
+
- `toDataSet(DynamicObjectCollection coll)`: 集合转数据集(DataSet)以执行高性能计算。
|
|
46
|
+
- `toDataSet(DynamicObjectCollection coll, String... selectFields)`: 选择字段转换。
|
|
47
|
+
- `fromDataSet(DataSet ds)`: 将计算结果转换回对象集合。
|
|
48
|
+
- `serialize(DynamicObject... dynArr)`: 序列化动态对象。
|
|
49
|
+
- `deSerialize(String serialized, DynamicObjectType dt)`: 反序列化动态对象。
|
|
50
|
+
|
|
51
|
+
### 5. 对象创建与克隆
|
|
52
|
+
- `clone(DynamicObject dyn)`: 深度克隆数据对象,默认清除主键值。
|
|
53
|
+
- `newDynamicObject(String formId)`: 根据表单标识生成新的动态对象。
|
|
54
|
+
- `newDynamicObject(DynamicObjectType dt)`: 根据类型生成新的动态对象。
|
|
55
|
+
|
|
56
|
+
### 6. 属性信息
|
|
57
|
+
- `getPropKeys(DynamicObject dyn)`: 获取属性标识集。
|
|
58
|
+
- `getPropKeys(DynamicObjectCollection coll)`: 获取集合属性标识集。
|
|
59
|
+
- `dump(DynamicObject dyn)`: 转储 DynamicObject 为 Map。
|
|
60
|
+
|
|
61
|
+
### 7. 状态判断
|
|
62
|
+
- `isNewCreate(DynamicObject dyn)`: 判断数据包是否为新增(不来源于数据库)。
|
|
63
|
+
|
|
64
|
+
## 示例代码
|
|
65
|
+
|
|
66
|
+
### 安全链式取值与分录统计
|
|
67
|
+
```java
|
|
68
|
+
package kd.cd.common.demo;
|
|
69
|
+
|
|
70
|
+
import kd.cd.common.util.DynamicObjectUtils;
|
|
71
|
+
import kd.bos.dataentity.entity.DynamicObjectCollection;
|
|
72
|
+
import java.math.BigDecimal;
|
|
73
|
+
|
|
74
|
+
public class DataDemo {
|
|
75
|
+
public void process(DynamicObject bill) {
|
|
76
|
+
// 1. 安全获取基础资料名称,无视空指针风险
|
|
77
|
+
String orgName = DynamicObjectUtils.nullSafeGet(bill, "org.name");
|
|
78
|
+
|
|
79
|
+
// 2. 统计分录中所有行特定金额之和
|
|
80
|
+
DynamicObjectCollection entry = bill.getDynamicObjectCollection("billentry");
|
|
81
|
+
BigDecimal totalAmount = DynamicObjectUtils.sumOf(entry, "amount");
|
|
82
|
+
|
|
83
|
+
// 3. 提取分录中所有物料ID
|
|
84
|
+
Set<Object> materialIds = DynamicObjectUtils.setOf(entry, "material.id");
|
|
85
|
+
|
|
86
|
+
// 4. 深路径扁平提取
|
|
87
|
+
Set<Object> allSubValues = DynamicObjectUtils.flatSetOf(bill, "entry.subentry.field");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 判断单据是否新增
|
|
93
|
+
```java
|
|
94
|
+
public void checkBillStatus(DynamicObject bill) {
|
|
95
|
+
if (DynamicObjectUtils.isNewCreate(bill)) {
|
|
96
|
+
// 新增单据,尚未保存到数据库
|
|
97
|
+
} else {
|
|
98
|
+
// 已存在的单据
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## 实践建议
|
|
104
|
+
1. **优先使用 Path 取值**: 在处理多级关联(如单据->物料->规格型号)时,使用 `flatSetOf("material.model")` 而不是逐层 `.get(...)`。
|
|
105
|
+
2. **批量查询原则**: 严禁在分录循环中查询数据库。应先提取分录中所有 ID(使用 `setOfIds`),执行一次批量查询后,再进行内存匹配。
|
|
106
|
+
3. **内存字段管理**: 动态添加的字段在使用 `toDataSet` 前需确保已注册在元数据中。
|
|
107
|
+
4. **序列化场景**: `serialize`/`deSerialize` 适用于跨进程传递或缓存存储。
|
|
108
|
+
|
|
109
|
+
## 常见坑位
|
|
110
|
+
1. **类型强转错误**: 从 `safeGetValue` 获取的值必须根据元数据定义的字段类型进行强转(如 `Long`, `BigDecimal`, `Date`),严禁凭经验判断。
|
|
111
|
+
2. **脏数据未提交**: 手动修改 `DynamicObject` 的值后,如果不希望触发操作插件的变更逻辑,需通过 `clearDirty` 控制。
|
|
112
|
+
3. **集合引用失效**: 对 `DynamicObjectCollection` 执行 `clear()` 后,之前获取的引用将变为空,操作前需确认状态。
|
|
113
|
+
4. **克隆后主键**: `clone` 方法默认清除主键值,如需保留主键请手动设置。
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# 实体元数据解析工具 (EntityUtils)
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
- 适用:查实体 key、字段属性、分录结构以及下拉/枚举元数据。
|
|
5
|
+
- 先抓:用 `EntityUtils` 拿实体标识、属性对象、分录字段和 `Combo` 信息。
|
|
6
|
+
- 跳转:操作数据值本身改读 `dynamic-object.md`;弹性域解析改读 `flex-prop.md`。
|
|
7
|
+
- 继续读全文:当你要写元数据驱动代码、动态取字段或调试实体结构时。
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
元数据(Metadata)驱动是苍穹的核心设计。`EntityUtils` (位于 `kd.cd.common.entity`) 对原生的实体元数据进行了深层封装,提供了获取实体标识、属性解析、下拉列表(Combo)以及分录结构的极简 API。旨在减少元数据读取时的深路径嵌套。
|
|
11
|
+
|
|
12
|
+
> **适用边界**
|
|
13
|
+
> ✅ 适用:获取实体标识/属性解析/下拉枚举/分录结构。
|
|
14
|
+
> ❌ 不适用:DynamicObject 数据操作请用 `dynamic-object.md`;弹性域字段解析请用 `flex-prop.md`。
|
|
15
|
+
|
|
16
|
+
## 核心类
|
|
17
|
+
- **`kd.cd.common.entity.EntityUtils`**: **元数据解析核心工具类**。
|
|
18
|
+
- **`kd.bos.entity.MainEntityType`**: 苍穹单据主实体元数据。
|
|
19
|
+
- **`kd.bos.dataentity.metadata.IDataEntityProperty`**: 实体属性元数据。
|
|
20
|
+
|
|
21
|
+
## 常用 API 方法
|
|
22
|
+
|
|
23
|
+
### 1. 实体标识与关键标识
|
|
24
|
+
- `getEntityId(String formId)`: **最常用**。根据表单标识获取其关联的数据实体名。
|
|
25
|
+
- `getPrimaryKey(String formId)`: 获取实体的 ID 字段 Key(通常为 "id")。
|
|
26
|
+
- `getBillNoKey(String formId)`: 获取实体的单据编号字段 Key(如 "billno")。
|
|
27
|
+
- `getBillStatusKey(String formId)`: 获取实体的单据状态字段 Key(如 "billstatus")。
|
|
28
|
+
- `getPkAndBillnoKey(String formId)`: 获取主键与单据编码字段标识(Pair)。
|
|
29
|
+
|
|
30
|
+
### 2. 属性解析与检索
|
|
31
|
+
- `getProperty(String formId, String field)`: 获取特定属性的元数据定义(单据头&单据体)。
|
|
32
|
+
- `getProperty(MainEntityType mainType, String field)`: 从主实体类型获取属性。
|
|
33
|
+
- `selectProperties(String formId, Predicate<IDataEntityProperty> predicate)`: 根据字段属性筛选字段。
|
|
34
|
+
- `getAllProperties(String formId)`: 获取表单实体中所有字段属性映射。
|
|
35
|
+
- `getEntryPropKeys(String formId, String entryKey)`: 获取分录包含的所有子字段 Key。
|
|
36
|
+
- `getEntryProperties(String formId, String entryKey)`: 获取分录字段属性映射。
|
|
37
|
+
- `getPropKeyWithPrefix(String formId, String field)`: 获取带父级前缀的字段标识(如 entry.subentry.field)。
|
|
38
|
+
- `getParentPropKey(String formId, String field)`: 获取字段所属父级属性标识。
|
|
39
|
+
|
|
40
|
+
### 3. 下拉与枚举
|
|
41
|
+
- `getComboItemMap(String formId, String comboKey)`: 获取下拉列表的所有枚举值(值 -> 名称)。
|
|
42
|
+
|
|
43
|
+
### 4. 类型与结构
|
|
44
|
+
- `getMainEntityType(String formId)`: 获取主实体类型(兼容PC布局)。
|
|
45
|
+
- `getDynamicObjectType(String formId)`: 获取动态对象类型。
|
|
46
|
+
- `getDynamicObjectType(String formId, String selectProperties)`: 获取仅含部分字段属性的动态对象类型。
|
|
47
|
+
- `getEntryType(String formId, String entryKey)`: 获取分录实体类型。
|
|
48
|
+
- `getTableDefine(String formId)`: 获取表单实体表定义。
|
|
49
|
+
|
|
50
|
+
### 5. 实体信息
|
|
51
|
+
- `getChsName(String formId)`: 获取表单实体中文描述名。
|
|
52
|
+
- `getAppId(String formId)`: 获取 AppId。
|
|
53
|
+
- `getDBRoute(String formId)`: 获取实体数据库路由。
|
|
54
|
+
- `getBaseDataQuoteType(String formId, String baseDataField)`: 获取基础资料引用类型。
|
|
55
|
+
- `getAliasState(String formId, String field)`: 获取字段数据库字段状态。
|
|
56
|
+
- `getLinkEntryRelation(String formId)`: 获取表单实体关联关系映射字段信息。
|
|
57
|
+
|
|
58
|
+
### 6. 数据校验工具
|
|
59
|
+
- `isEmptyPk(Object pkValue)`: **最常用**。安全判定单据主键是否为空(兼容 0L 或空字符串)。
|
|
60
|
+
- `isNotEmptyPk(Object pkValue)`: 判定主键非空。
|
|
61
|
+
- `checkNotEmptyPk(Object pkValue, String expr)`: 校验主键值非空,为空时抛出异常。
|
|
62
|
+
|
|
63
|
+
### 7. 扁平提取(调试用)
|
|
64
|
+
- `flatListValue(DynamicObject dataEntity, String field)`: 扁平列出主实体中某字段的所有值。
|
|
65
|
+
- `peek(Object o)`: 预览实体结构(仅调试)。
|
|
66
|
+
|
|
67
|
+
## 示例代码
|
|
68
|
+
|
|
69
|
+
### 动态获取单据显示名
|
|
70
|
+
```java
|
|
71
|
+
package kd.cd.common.demo;
|
|
72
|
+
|
|
73
|
+
import kd.cd.common.entity.EntityUtils;
|
|
74
|
+
|
|
75
|
+
public class MetaDemo {
|
|
76
|
+
public void getInfo(String formId, Object pkValue) {
|
|
77
|
+
// 1. 获取实体标识
|
|
78
|
+
String entityId = EntityUtils.getEntityId(formId);
|
|
79
|
+
|
|
80
|
+
// 2. 获取主键和编号对应的 Key
|
|
81
|
+
String pkKey = EntityUtils.getPrimaryKey(formId);
|
|
82
|
+
String noKey = EntityUtils.getBillNoKey(formId);
|
|
83
|
+
|
|
84
|
+
// 3. 获取下拉列表的中文字符
|
|
85
|
+
Map<String, String> items = EntityUtils.getComboItemMap(formId, "billstatus");
|
|
86
|
+
|
|
87
|
+
// 4. 获取实体中文名
|
|
88
|
+
String chsName = EntityUtils.getChsName(formId);
|
|
89
|
+
|
|
90
|
+
// 5. 校验主键非空
|
|
91
|
+
if (EntityUtils.isEmptyPk(pkValue)) {
|
|
92
|
+
// 单据尚未保存
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 获取分录字段信息
|
|
99
|
+
```java
|
|
100
|
+
public void analyzeEntry(String formId, String entryKey) {
|
|
101
|
+
// 获取分录所有字段标识
|
|
102
|
+
Set<String> fieldKeys = EntityUtils.getEntryPropKeys(formId, entryKey);
|
|
103
|
+
|
|
104
|
+
// 获取分录字段属性映射
|
|
105
|
+
Map<String, IDataEntityProperty> properties = EntityUtils.getEntryProperties(formId, entryKey);
|
|
106
|
+
|
|
107
|
+
// 获取带前缀的字段标识
|
|
108
|
+
String fullKey = EntityUtils.getPropKeyWithPrefix(formId, "entry.field");
|
|
109
|
+
// 结果: "entry.field" 或 "entity.entry.field"
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## 实践建议
|
|
114
|
+
1. **优先使用 getBillNoKey**: 在通用插件中获取单据编号,不要写死 "billno",以应对客户在设计器中对字段标识的调整。
|
|
115
|
+
2. **分录字段前缀**: 拼接分录字段名时,建议使用 `getPropKeyWithPrefix` 自动补全前缀。
|
|
116
|
+
3. **缓存重用**: 对于元数据的频繁读取,建议在方法内部缓存 `MainEntityType` 的引用。
|
|
117
|
+
4. **主键判空**: 使用 `isEmptyPk` 而非 `== null`,因为苍穹主键默认为 0L。
|
|
118
|
+
|
|
119
|
+
## 常见坑位
|
|
120
|
+
1. **基础资料扩展失效**: 对于动态扩展的字段,如果扩展未发布,`getProperty` 会返回 null。
|
|
121
|
+
2. **区分 FormId 与 EntityId**: 表单标识(UI)和实体标识(DB)有时不同(如基础资料扩展),调用时务必核实参数。
|
|
122
|
+
3. **主键默认值**: 苍穹主键默认为 0L,使用 `isEmptyPk` 可以精准识别单据是否已入库。
|
|
123
|
+
4. **属性对象共享**: `getProperty` 返回的对象是全局缓存共用的,禁止对其进行 set 操作。
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# 插件事件生命周期图
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
|
|
5
|
+
- 适用:你已经命中插件类型,但不确定事件触发顺序、该把逻辑放在哪个阶段时,先读本页。
|
|
6
|
+
- 先抓:先看对应插件类型的生命周期图,再看“放置策略速查”。
|
|
7
|
+
- 边界:本页只解决“事件先后顺序 + 适合放什么逻辑”;具体方法签名、原生事件全集仍回各插件文档确认。
|
|
8
|
+
- 跳转:
|
|
9
|
+
- 表单 / 单据:`plugin-base.md`、`plugin-form.md`、`plugin-bill.md`
|
|
10
|
+
- 列表:`plugin-base.md`、`plugin-list.md`
|
|
11
|
+
- 操作:`plugin-base.md`、`plugin-operation.md`
|
|
12
|
+
- 转换:`plugin-botp.md`
|
|
13
|
+
- 反写:`plugin-writeback.md`
|
|
14
|
+
|
|
15
|
+
## 一页总原则
|
|
16
|
+
|
|
17
|
+
- `initialize`:做轻量初始化;不要注册监听,不要做 UI 可见性/启用状态逻辑。
|
|
18
|
+
- `registerListener`:只注册监听;不要依赖已绑定的数据,不要在这里 `model.getValue(...)`。
|
|
19
|
+
- `createNewData` / `loadData` / `afterLoadData`:做数据包初始化、补字段、加载后整理。
|
|
20
|
+
- `beforeBindData` / `afterBindData`:处理绑定前后和 UI 状态;不要在绑定阶段改数据对象。
|
|
21
|
+
- 操作插件:先区分事务前、事务中、事务后;明确规则优先放校验器。
|
|
22
|
+
- 转换 / 反写插件:先看当前是在“转换阶段”还是“回写阶段”,再判断事件位置。
|
|
23
|
+
|
|
24
|
+
## 表单 / 单据插件
|
|
25
|
+
|
|
26
|
+
单据插件继承动态表单生命周期;已有单据更常落在 `loadData/afterLoadData`,新建单据更常落在 `createNewData/afterCreateNewData`。
|
|
27
|
+
|
|
28
|
+
```mermaid
|
|
29
|
+
flowchart TD
|
|
30
|
+
A["preOpenForm"] --> B["initialize"]
|
|
31
|
+
B --> C["registerListener"]
|
|
32
|
+
C --> D{"新建还是加载已有数据"}
|
|
33
|
+
D -->|新建| E["createNewData"]
|
|
34
|
+
E --> F["afterCreateNewData"]
|
|
35
|
+
D -->|加载已有| G["loadData"]
|
|
36
|
+
G --> H["afterLoadData"]
|
|
37
|
+
F --> I["beforeBindData"]
|
|
38
|
+
H --> I
|
|
39
|
+
I --> J["afterBindData"]
|
|
40
|
+
J --> K["propertyChanged / click / beforeDoOperation / afterDoOperation"]
|
|
41
|
+
K --> L["beforeClosed"]
|
|
42
|
+
L --> M["destory"]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 放置策略
|
|
46
|
+
|
|
47
|
+
| 事件 | 适合放什么 | 不要放什么 |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `initialize` | 轻量初始化、上下文准备 | 监听注册、UI 状态逻辑 |
|
|
50
|
+
| `registerListener` | `add*Listener`、监听器注册 | `model.getValue(...)`、联动赋值 |
|
|
51
|
+
| `createNewData` | 新建默认值、数据包初始化 | 控件可见性 / 启用状态 |
|
|
52
|
+
| `afterLoadData` | 已有单据加载后整理 | 事务级校验 |
|
|
53
|
+
| `beforeBindData` / `afterBindData` | UI 刷新前后、界面状态控制 | `setValue(...)`、改数据包 |
|
|
54
|
+
| `propertyChanged` | 字段联动、即时补值 | 跨事务级复杂状态流转 |
|
|
55
|
+
|
|
56
|
+
## 列表插件
|
|
57
|
+
|
|
58
|
+
列表插件没有 `createNewData/loadData` 这一段,重点是列表绑定前后和列表交互事件。
|
|
59
|
+
|
|
60
|
+
```mermaid
|
|
61
|
+
flowchart TD
|
|
62
|
+
A["preOpenForm"] --> B["initialize"]
|
|
63
|
+
B --> C["registerListener"]
|
|
64
|
+
C --> D["beforeBindData"]
|
|
65
|
+
D --> E["afterBindData"]
|
|
66
|
+
E --> F["itemClick / listRowClick / setFilter / beforeShowBill"]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 放置策略
|
|
70
|
+
|
|
71
|
+
| 事件 | 适合放什么 | 不要放什么 |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| `registerListener` | 列表按钮、行点击、超链接等监听注册 | 依赖已选中行的数据处理 |
|
|
74
|
+
| `beforeBindData` | 绑定前过滤准备 | 直接改行数据对象 |
|
|
75
|
+
| `afterBindData` | 列表展示、过滤容器状态协同 | 批量持久化写库 |
|
|
76
|
+
| `itemClick` / `listRowClick` | 批量动作入口、打开页面、交互编排 | 事务内核心业务逻辑 |
|
|
77
|
+
|
|
78
|
+
## 操作插件
|
|
79
|
+
|
|
80
|
+
操作插件运行在服务端事务链路,要先分清“字段准备”“校验”“事务内处理”“事务后处理”。
|
|
81
|
+
|
|
82
|
+
```mermaid
|
|
83
|
+
flowchart TD
|
|
84
|
+
A["onPreparePropertys"] --> B["onAddValidators"]
|
|
85
|
+
B --> C["beforeExecuteOperationTransaction"]
|
|
86
|
+
C --> D["beginOperationTransaction"]
|
|
87
|
+
D --> E["endOperationTransaction"]
|
|
88
|
+
E --> F["afterExecuteOperationTransaction"]
|
|
89
|
+
F --> G["onReturnOperation"]
|
|
90
|
+
D --> R["rollbackOperation"]
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 放置策略
|
|
94
|
+
|
|
95
|
+
| 事件 | 适合放什么 | 不要放什么 |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| `onPreparePropertys` | 补操作所需字段 | 业务校验、状态写回 |
|
|
98
|
+
| `onAddValidators` | 注册校验器、前置阻断 | 事务内数据修改 |
|
|
99
|
+
| `beforeExecuteOperationTransaction` | 最后整理、轻量兜底校验 | 大量规则校验堆叠 |
|
|
100
|
+
| `beginOperationTransaction` / `endOperationTransaction` | 事务内同步处理、状态更新 | 事务后通知类逻辑 |
|
|
101
|
+
| `afterExecuteOperationTransaction` | 消息通知、日志、外部后续动作 | 再修改主单据事务数据 |
|
|
102
|
+
|
|
103
|
+
## 转换插件
|
|
104
|
+
|
|
105
|
+
转换插件关注源单取数、目标单创建、字段映射和关联关系生成。先区分“下推/选单业务动作”还是“转换规则扩展”。
|
|
106
|
+
|
|
107
|
+
```mermaid
|
|
108
|
+
flowchart TD
|
|
109
|
+
A["initVariable"] --> B["afterBuildQueryParemeter"]
|
|
110
|
+
B --> C["beforeBuildRowCondition"]
|
|
111
|
+
C --> D["afterBuildRowCondition"]
|
|
112
|
+
D --> E["beforeGetSourceData"]
|
|
113
|
+
E --> F["afterGetSourceData"]
|
|
114
|
+
F --> G["beforeBuildGroupMode"]
|
|
115
|
+
G --> H["beforeCreateTarget"]
|
|
116
|
+
H --> I["afterCreateTarget"]
|
|
117
|
+
I --> J["afterFieldMapping"]
|
|
118
|
+
J --> K["afterBizRule"]
|
|
119
|
+
K --> L["beforeCreateLink"]
|
|
120
|
+
L --> M["afterCreateLink"]
|
|
121
|
+
M --> N["afterBuildDrawFilter"]
|
|
122
|
+
N --> O["afterConvert"]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 放置策略
|
|
126
|
+
|
|
127
|
+
| 事件 | 适合放什么 | 不要放什么 |
|
|
128
|
+
|---|---|---|
|
|
129
|
+
| `initVariable` | 识别下推/选单上下文 | 直接写目标单字段 |
|
|
130
|
+
| `beforeGetSourceData` / `afterGetSourceData` | 源单过滤、补第三方数据 | 映射完成后的兜底修正 |
|
|
131
|
+
| `afterFieldMapping` | 映射后补值 | 过早取消关联 |
|
|
132
|
+
| `afterBizRule` | 规则执行后的最终修正 | 大量外部 IO |
|
|
133
|
+
| `beforeCreateLink` / `afterCreateLink` | 调整上下游关联关系 | 随意取消导致追踪断裂 |
|
|
134
|
+
|
|
135
|
+
## 反写插件
|
|
136
|
+
|
|
137
|
+
反写插件是 BOTP 回写阶段的专用链路,不等于一般意义上的“更新关联实体”。
|
|
138
|
+
|
|
139
|
+
```mermaid
|
|
140
|
+
flowchart TD
|
|
141
|
+
A["preparePropertys"] --> B["beforeTrack"]
|
|
142
|
+
B --> C["beforeCreateArticulationRow"]
|
|
143
|
+
C --> D["beforeExecWriteBackRule"]
|
|
144
|
+
D --> E["afterCalcWriteValue"]
|
|
145
|
+
E --> F["beforeReadSourceBill"]
|
|
146
|
+
F --> G["afterReadSourceBill"]
|
|
147
|
+
G --> H["afterCommitAmount"]
|
|
148
|
+
H --> I["beforeExcessCheck"]
|
|
149
|
+
I --> J["afterExcessCheck"]
|
|
150
|
+
J --> K["beforeCloseRow"]
|
|
151
|
+
K --> L["afterCloseRow"]
|
|
152
|
+
L --> M["beforeSaveTrans"]
|
|
153
|
+
M --> N["beforeSaveSourceBill"]
|
|
154
|
+
N --> O["afterSaveSourceBill"]
|
|
155
|
+
O --> P["finishWriteBack"]
|
|
156
|
+
N --> R["rollbackSave"]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### 放置策略
|
|
160
|
+
|
|
161
|
+
| 事件 | 适合放什么 | 不要放什么 |
|
|
162
|
+
|---|---|---|
|
|
163
|
+
| `preparePropertys` / `beforeReadSourceBill` | 补字段准备 | 直接做反写结果修正 |
|
|
164
|
+
| `beforeExecWriteBackRule` / `afterCalcWriteValue` | 控制规则是否执行、修正反写值 | 事务补偿逻辑 |
|
|
165
|
+
| `beforeExcessCheck` / `afterExcessCheck` | 超额校验、提示策略 | 一刀切取消全部检查 |
|
|
166
|
+
| `beforeSaveTrans` / `rollbackSave` | 外部补偿、第三方一致性闭环 | 忽略失败回滚 |
|
|
167
|
+
| `finishWriteBack` | 释放网控、缓存句柄等资源 | 留资源不释放 |
|
|
168
|
+
|
|
169
|
+
## 常见错位速查
|
|
170
|
+
|
|
171
|
+
| 误放位置 | 常见后果 | 正确位置 |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| 在 `initialize()` 中注册监听或写 UI 状态 | 生命周期过早,逻辑失效或错时 | `registerListener` / `afterBindData` |
|
|
174
|
+
| 在 `registerListener` 中读模型值 | 数据尚未绑定 | `afterBindData` / `propertyChanged` |
|
|
175
|
+
| 在 `beforeBindData` / `afterBindData` 中 `setValue(...)` | 绑定阶段改数据,容易出错 | `createNewData` / `afterLoadData` / `propertyChanged` / 保存前 |
|
|
176
|
+
| 在 UI 插件中承担事务级校验或状态流转 | 与服务端状态机冲突 | 操作插件 |
|
|
177
|
+
| 把“业务上说反写”直接理解成反写插件 | 场景误判 | 先判断是不是普通实体更新,只有明确插件语义时才走反写插件 |
|
|
178
|
+
|
|
179
|
+
## 继续读取建议
|
|
180
|
+
|
|
181
|
+
- 只是不确定“该放哪个事件”:本页足够。
|
|
182
|
+
- 要确认方法签名:回 [plugin-base.md](plugin-base.md) 或对应原生插件文档。
|
|
183
|
+
- 要确认具体控件/字段联动做法:回对应 `form-utils.md`、`plugin-form.md`、`plugin-bill.md`。
|
|
184
|
+
- 要确认转换 / 反写事件细节:回 `plugin-botp.md`、`plugin-writeback.md`。
|