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
package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportListDataPlugin.java
ADDED
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
package kd.cd.common.snippets;
|
|
2
|
+
|
|
3
|
+
import kd.bos.algo.Algo;
|
|
4
|
+
import kd.bos.algo.CustomAggFunction;
|
|
5
|
+
import kd.bos.algo.DataSet;
|
|
6
|
+
import kd.bos.algo.DataSetBuilder;
|
|
7
|
+
import kd.bos.algo.DataType;
|
|
8
|
+
import kd.bos.algo.Field;
|
|
9
|
+
import kd.bos.algo.Row;
|
|
10
|
+
import kd.bos.algo.RowMeta;
|
|
11
|
+
import kd.bos.algo.RowMetaFactory;
|
|
12
|
+
import kd.bos.dataentity.entity.DynamicObject;
|
|
13
|
+
import kd.bos.dataentity.entity.DynamicObjectCollection;
|
|
14
|
+
import kd.bos.dataentity.entity.LocaleString;
|
|
15
|
+
import kd.bos.db.DB;
|
|
16
|
+
import kd.bos.db.DBRoute;
|
|
17
|
+
import kd.bos.entity.report.AbstractReportColumn;
|
|
18
|
+
import kd.bos.entity.report.AbstractReportListDataPlugin;
|
|
19
|
+
import kd.bos.entity.report.FilterInfo;
|
|
20
|
+
import kd.bos.entity.report.ReportColumn;
|
|
21
|
+
import kd.bos.entity.report.ReportQueryParam;
|
|
22
|
+
import kd.bos.orm.query.QCP;
|
|
23
|
+
import kd.bos.orm.query.QFilter;
|
|
24
|
+
import kd.bos.servicehelper.QueryServiceHelper;
|
|
25
|
+
import kd.cd.core.util.BigDecimalUtils;
|
|
26
|
+
import kd.cd.core.util.CollectionUtils;
|
|
27
|
+
import kd.cd.common.util.AlgoUtils;
|
|
28
|
+
import kd.cd.common.util.DynamicObjectUtils;
|
|
29
|
+
import kd.cd.common.util.SelectFieldBuilder;
|
|
30
|
+
|
|
31
|
+
import java.math.BigDecimal;
|
|
32
|
+
import java.util.ArrayList;
|
|
33
|
+
import java.util.Date;
|
|
34
|
+
import java.util.List;
|
|
35
|
+
import java.util.Set;
|
|
36
|
+
import java.util.stream.Collectors;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 报表取数插件示例 + DataSet Cookbook。
|
|
40
|
+
* <p>
|
|
41
|
+
* 适用插件:报表取数插件
|
|
42
|
+
* 优先封装:AlgoUtils、SelectFieldBuilder、DynamicObjectUtils
|
|
43
|
+
* 原生兜底:AbstractReportListDataPlugin、DataSet、QueryServiceHelper、DB
|
|
44
|
+
* 相关 lint 规则:RESOURCE-004、STYLE-015
|
|
45
|
+
* <p>
|
|
46
|
+
* 使用场景:
|
|
47
|
+
* 1. query() 入口:FilterInfo 获取条件 → QFilter 构建 → 多数据源查询 → DataSet 处理;
|
|
48
|
+
* 2. getColumns() 动态定义报表列;
|
|
49
|
+
* 3. DataSet 全场景 Cookbook:select / filter / groupBy / join / union /
|
|
50
|
+
* addField / orderBy / map / copy / 互转 / SQL / RowMeta。
|
|
51
|
+
* <p>
|
|
52
|
+
* <b>注意:DataSet 被迭代器访问或 for 循环遍历后会自动关闭,关闭后无法再做任何数据集操作。</b>
|
|
53
|
+
* 如果迭代后还需要继续操作该 DataSet,必须在迭代前先调用 {@code copy()}。
|
|
54
|
+
*/
|
|
55
|
+
public class SampleReportListDataPlugin extends AbstractReportListDataPlugin {
|
|
56
|
+
|
|
57
|
+
// ==================== 常量定义 ====================
|
|
58
|
+
/** 业务实体标识(替换为实际的单据标识) */
|
|
59
|
+
private static final String ENTITY_BILL_A = "kdcd_sample_bill_a";
|
|
60
|
+
private static final String ENTITY_BILL_B = "kdcd_sample_bill_b";
|
|
61
|
+
|
|
62
|
+
// ==================== 一、动态列定义(可选) ====================
|
|
63
|
+
/**
|
|
64
|
+
* 动态定义报表列。
|
|
65
|
+
* 适用场景:列不固定(如根据查询条件动态增减列)、需要设置超链接、特殊列类型等。
|
|
66
|
+
* 如果报表列已在设计器中配置好,则无需覆写此方法。
|
|
67
|
+
*/
|
|
68
|
+
@Override
|
|
69
|
+
public List<AbstractReportColumn> getColumns(List<AbstractReportColumn> columns) throws Throwable {
|
|
70
|
+
// 方式一:通过二维数组批量定义列(推荐,简洁)
|
|
71
|
+
String[][] columnDefs = {
|
|
72
|
+
// {字段标识, 列标题, 列宽度}
|
|
73
|
+
{"kdcd_order", "序号", "50"},
|
|
74
|
+
{"kdcd_item_name", "项目名称", "150"},
|
|
75
|
+
{"kdcd_budget_amt", "预算金额", "120"},
|
|
76
|
+
{"kdcd_actual_amt", "实际金额", "120"},
|
|
77
|
+
{"kdcd_diff_amt", "差异金额", "120"},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
for (String[] def : columnDefs) {
|
|
81
|
+
ReportColumn column = new ReportColumn();
|
|
82
|
+
column.setFieldKey(def[0]);
|
|
83
|
+
column.setCaption(new LocaleString(def[1]));
|
|
84
|
+
column.setWidth(new LocaleString(def[2]));
|
|
85
|
+
// 字段类型:TYPE_TEXT / TYPE_AMOUNT / TYPE_DECIMAL / TYPE_INTEGER / TYPE_DATE
|
|
86
|
+
column.setFieldType(ReportColumn.TYPE_TEXT);
|
|
87
|
+
// 如需设置超链接
|
|
88
|
+
// column.setHyperlink(true);
|
|
89
|
+
columns.add(column);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return columns;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ==================== 二、核心取数方法 ====================
|
|
96
|
+
/**
|
|
97
|
+
* 报表取数入口。
|
|
98
|
+
* 整体流程:获取过滤条件 → 构建 QFilter → 查询多个数据源 → DataSet 处理 → 返回结果
|
|
99
|
+
*/
|
|
100
|
+
@Override
|
|
101
|
+
public DataSet query(ReportQueryParam reportQueryParam, Object o) throws Throwable {
|
|
102
|
+
// ---------- Step 1: 获取查询条件 ----------
|
|
103
|
+
FilterInfo filterInfo = reportQueryParam.getFilter();
|
|
104
|
+
|
|
105
|
+
// 获取单个基础资料(组织)
|
|
106
|
+
DynamicObject org = filterInfo.getDynamicObject("kdcd_org");
|
|
107
|
+
// 前置校验已在 FormPlugin.verifyQuery() 中完成,此处做安全兵底
|
|
108
|
+
if (org == null) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
long orgId = org.getLong("id");
|
|
112
|
+
|
|
113
|
+
// 获取多选基础资料(项目列表)
|
|
114
|
+
DynamicObjectCollection projectCollection = filterInfo.getDynamicObjectCollection("kdcd_project");
|
|
115
|
+
|
|
116
|
+
// 获取日期
|
|
117
|
+
Date endDate = filterInfo.getDate("kdcd_date");
|
|
118
|
+
// 前置校验已在 FormPlugin.verifyQuery() 中完成,此处做安全兵底
|
|
119
|
+
if (endDate == null) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ---------- Step 2: 构建过滤条件 ----------
|
|
124
|
+
// 单据A的过滤条件(已审核)
|
|
125
|
+
QFilter filterA = new QFilter("billstatus", QCP.equals, "C");
|
|
126
|
+
filterA.and("org.id", QCP.equals, orgId);
|
|
127
|
+
filterA.and("bizdate", QCP.less_equals, endDate);
|
|
128
|
+
|
|
129
|
+
// 单据B的过滤条件(已提交 + 已审核)
|
|
130
|
+
QFilter filterB = new QFilter("billstatus", QCP.in, new String[]{"B", "C"});
|
|
131
|
+
filterB.and("org.id", QCP.equals, orgId);
|
|
132
|
+
filterB.and("bizdate", QCP.less_equals, endDate);
|
|
133
|
+
|
|
134
|
+
// 项目过滤(如果选择了项目)
|
|
135
|
+
if (CollectionUtils.isNotEmpty(projectCollection)) {
|
|
136
|
+
Set<Long> projectIds = projectCollection.stream()
|
|
137
|
+
.map(p -> p.getLong("id"))
|
|
138
|
+
.collect(Collectors.toSet());
|
|
139
|
+
filterA.and("kdcd_project.id", QCP.in, projectIds);
|
|
140
|
+
filterB.and("kdcd_project.id", QCP.in, projectIds);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ---------- Step 3: 查询数据源 ----------
|
|
144
|
+
// 方式一:通过 QueryServiceHelper.queryDataSet 查询实体(推荐)
|
|
145
|
+
// 参数:(调用者标识, 实体标识, 查询字段, QFilter数组, 排序)
|
|
146
|
+
// 使用 SelectFieldBuilder 构建查询字段(支持表达式别名,比字符串拼接更清晰)
|
|
147
|
+
String selectFieldsA = new SelectFieldBuilder()
|
|
148
|
+
.appendAll("id", "billno", "kdcd_project", "billstatus")
|
|
149
|
+
.append("kdcd_project.name", "project_name")
|
|
150
|
+
.append("kdcd_amount", "budget_amt")
|
|
151
|
+
.toString();
|
|
152
|
+
DataSet dataSetA = QueryServiceHelper.queryDataSet(
|
|
153
|
+
getClass().getName(), ENTITY_BILL_A, selectFieldsA,
|
|
154
|
+
new QFilter[]{filterA}, null);
|
|
155
|
+
|
|
156
|
+
String selectFieldsB = new SelectFieldBuilder()
|
|
157
|
+
.appendAll("id", "kdcd_project")
|
|
158
|
+
.append("entryentity.amount", "actual_amt")
|
|
159
|
+
.toString();
|
|
160
|
+
DataSet dataSetB = QueryServiceHelper.queryDataSet(
|
|
161
|
+
getClass().getName(), ENTITY_BILL_B, selectFieldsB,
|
|
162
|
+
new QFilter[]{filterB}, null);
|
|
163
|
+
|
|
164
|
+
// ---------- Step 4: DataSet 数据处理(详见下方 DataSet Cookbook) ----------
|
|
165
|
+
|
|
166
|
+
// 4.1 分组聚合:按项目汇总实际金额
|
|
167
|
+
DataSet actualSummary = dataSetB
|
|
168
|
+
.groupBy(new String[]{"kdcd_project"})
|
|
169
|
+
.sum("actual_amt")
|
|
170
|
+
.finish();
|
|
171
|
+
|
|
172
|
+
// 4.2 关联查询:预算数据 LEFT JOIN 实际数据
|
|
173
|
+
DataSet joinResult = dataSetA
|
|
174
|
+
.leftJoin(actualSummary)
|
|
175
|
+
.on("kdcd_project", "kdcd_project")
|
|
176
|
+
.select("kdcd_project", "project_name", "budget_amt", "actual_amt")
|
|
177
|
+
.finish();
|
|
178
|
+
|
|
179
|
+
// 4.3 添加计算字段:差异金额 = 预算 - 实际
|
|
180
|
+
DataSet withDiff = joinResult.addField("budget_amt - actual_amt", "diff_amt");
|
|
181
|
+
|
|
182
|
+
// 4.4 过滤:只保留有差异的数据
|
|
183
|
+
// DataSet filtered = withDiff.filter("diff_amt != 0");
|
|
184
|
+
|
|
185
|
+
// 4.5 排序
|
|
186
|
+
DataSet sorted = withDiff.orderBy(new String[]{"project_name"});
|
|
187
|
+
|
|
188
|
+
// 4.6 字段重命名为报表列标识
|
|
189
|
+
DataSet result = sorted.select(
|
|
190
|
+
"project_name as kdcd_item_name",
|
|
191
|
+
"budget_amt as kdcd_budget_amt",
|
|
192
|
+
"actual_amt as kdcd_actual_amt",
|
|
193
|
+
"diff_amt as kdcd_diff_amt"
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
// ---------- Step 5: 可选 —— 添加固定汇总行 ----------
|
|
197
|
+
DataSet totalRow = buildTotalRow(result.copy());
|
|
198
|
+
DataSet finalResult = totalRow.union(result);
|
|
199
|
+
|
|
200
|
+
return finalResult;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ==================== 三、辅助方法 ====================
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* 构建汇总行(手动创建 DataSet)。
|
|
207
|
+
* 通过 AlgoUtils.newDataSet 创建自定义 DataSet。
|
|
208
|
+
*/
|
|
209
|
+
private DataSet buildTotalRow(DataSet sourceData) {
|
|
210
|
+
// 先汇总(注意:for 循环结束后 sourceData 会自动关闭,所以调用方传入的是 result.copy())
|
|
211
|
+
BigDecimal totalBudget = BigDecimal.ZERO;
|
|
212
|
+
BigDecimal totalActual = BigDecimal.ZERO;
|
|
213
|
+
for (Row row : sourceData) {
|
|
214
|
+
totalBudget = BigDecimalUtils.add(totalBudget, BigDecimalUtils.nullToZero(row.getBigDecimal("kdcd_budget_amt")));
|
|
215
|
+
totalActual = BigDecimalUtils.add(totalActual, BigDecimalUtils.nullToZero(row.getBigDecimal("kdcd_actual_amt")));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// 构建行数据
|
|
219
|
+
List<Object[]> rows = new ArrayList<>();
|
|
220
|
+
rows.add(new Object[]{
|
|
221
|
+
"合计", // kdcd_item_name
|
|
222
|
+
totalBudget, // kdcd_budget_amt
|
|
223
|
+
totalActual, // kdcd_actual_amt
|
|
224
|
+
BigDecimalUtils.subtract(totalBudget, totalActual) // kdcd_diff_amt
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// 使用 AlgoUtils.newDataSet 创建本地 DataSet(替代 CollectionInput + Algo.create 模式)
|
|
228
|
+
return AlgoUtils.newDataSet(
|
|
229
|
+
new String[]{"kdcd_item_name", "kdcd_budget_amt", "kdcd_actual_amt", "kdcd_diff_amt"},
|
|
230
|
+
new DataType[]{DataType.StringType, DataType.BigDecimalType, DataType.BigDecimalType, DataType.BigDecimalType},
|
|
231
|
+
rows
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* 使用 DataSetBuilder 手动构建 DataSet(另一种方式)。
|
|
237
|
+
* 适用场景:需要逐行追加数据时。
|
|
238
|
+
*/
|
|
239
|
+
private DataSet buildDataSetWithBuilder() {
|
|
240
|
+
Field[] fields = new Field[]{
|
|
241
|
+
new Field("name", DataType.StringType),
|
|
242
|
+
new Field("amount", DataType.BigDecimalType),
|
|
243
|
+
};
|
|
244
|
+
RowMeta rowMeta = new RowMeta(fields);
|
|
245
|
+
DataSetBuilder builder = Algo.create(getClass().getName()).createDataSetBuilder(rowMeta);
|
|
246
|
+
|
|
247
|
+
// 逐行追加
|
|
248
|
+
builder.append(new Object[]{"行1", new BigDecimal("100.00")});
|
|
249
|
+
builder.append(new Object[]{"行2", new BigDecimal("200.00")});
|
|
250
|
+
|
|
251
|
+
return builder.build();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ===================================================================
|
|
255
|
+
// DataSet 数据处理 Cookbook —— 各种场景用法示例
|
|
256
|
+
// 以下方法仅作为参考示例
|
|
257
|
+
// ===================================================================
|
|
258
|
+
|
|
259
|
+
// -------------------- 1. select 字段选择与表达式 --------------------
|
|
260
|
+
private void selectExamples(DataSet ds) {
|
|
261
|
+
// 1.1 基本字段选择
|
|
262
|
+
DataSet ds1 = ds.select("id", "billno", "kdcd_amount");
|
|
263
|
+
|
|
264
|
+
// 1.2 字段重命名(as 别名)
|
|
265
|
+
DataSet ds2 = ds.select("kdcd_project.name as project_name", "kdcd_amount as amt");
|
|
266
|
+
|
|
267
|
+
// 1.3 表达式计算新字段
|
|
268
|
+
DataSet ds3 = ds.select(
|
|
269
|
+
"billno",
|
|
270
|
+
"kdcd_amount * 1.13 as amount_with_tax", // 乘以税率
|
|
271
|
+
"'固定值' as kdcd_type" // 常量字段
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
// 1.4 字段拼接(字符串拼接用 +)
|
|
275
|
+
DataSet ds4 = ds.select(
|
|
276
|
+
"\" \" + accountNumber + ' ' + accname as kdcd_budget_item", // 缩进 + 编码 + 名称
|
|
277
|
+
"kdcd_init_budget",
|
|
278
|
+
"kdcd_actual_amt"
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
// 1.5 select 保留所有原字段 + 追加新字段(用 addField)
|
|
282
|
+
DataSet ds5 = ds.addField("budget_amt - actual_amt", "diff_amt")
|
|
283
|
+
.addField("5", "sort_order"); // 添加常量排序字段
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// -------------------- 2. filter 条件过滤 --------------------
|
|
287
|
+
private void filterExamples(DataSet ds) {
|
|
288
|
+
// 2.1 字符串表达式过滤(类SQL语法)
|
|
289
|
+
DataSet ds1 = ds.filter("billstatus = 'C'"); // 等于
|
|
290
|
+
DataSet ds2 = ds.filter("kdcd_amount > 0 and kdcd_amount < 10000"); // 范围
|
|
291
|
+
DataSet ds3 = ds.filter("kdcd_version_number = 1.0"); // 数值
|
|
292
|
+
DataSet ds4 = ds.filter("kdcd_type = 'er_expenseitemedit'"); // 字符串
|
|
293
|
+
DataSet ds5 = ds.filter("accountNumber != null"); // 非空
|
|
294
|
+
DataSet ds6 = ds.filter("kdcd_item_sort != 0"); // 非零
|
|
295
|
+
DataSet ds7 = ds.filter("billstatus = 'C' and kdcd_version_number = 1.0"); // 组合条件
|
|
296
|
+
|
|
297
|
+
// 2.2 过滤后保留有差异的行 —— 预警报表场景
|
|
298
|
+
DataSet ds8 = ds.filter("kdcd_actual_amt > kdcd_adj_budget"); // 实际发生数 > 调整后预算
|
|
299
|
+
|
|
300
|
+
// 2.3 null 值过滤
|
|
301
|
+
DataSet ds9 = ds.filter("predictdepre != null and predictdepre != 0");
|
|
302
|
+
|
|
303
|
+
// 2.4 自定义过滤逻辑(使用 AlgoUtils.filter 简化 FilterFunction 匿名类)
|
|
304
|
+
List<String> targetIds = new ArrayList<>(); // 假设已构建
|
|
305
|
+
targetIds.add("id_001");
|
|
306
|
+
targetIds.add("id_002");
|
|
307
|
+
DataSet ds10 = AlgoUtils.filter(ds, row -> {
|
|
308
|
+
String value = row.getString("assgrp_value");
|
|
309
|
+
if (value != null) {
|
|
310
|
+
for (String targetId : targetIds) {
|
|
311
|
+
if (value.contains(targetId)) {
|
|
312
|
+
return true; // 包含目标ID则保留
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return false; // 否则过滤掉
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// -------------------- 3. groupBy 分组聚合 --------------------
|
|
321
|
+
private void groupByExamples(DataSet ds) {
|
|
322
|
+
// 3.1 单字段分组 + 单个求和
|
|
323
|
+
DataSet ds1 = ds.groupBy(new String[]{"kdcd_project"})
|
|
324
|
+
.sum("kdcd_amount")
|
|
325
|
+
.finish();
|
|
326
|
+
|
|
327
|
+
// 3.2 多字段分组 + 多个求和
|
|
328
|
+
DataSet ds2 = ds.groupBy(new String[]{"kdcd_expense", "kdcd_expense_name", "kdcd_cost", "kdcd_cost_name"})
|
|
329
|
+
.sum("kdcd_init_budget")
|
|
330
|
+
.sum("kdcd_adj_budget")
|
|
331
|
+
.sum("kdcd_actual_amt")
|
|
332
|
+
.finish();
|
|
333
|
+
|
|
334
|
+
// 3.3 全局聚合(不分组,求总计)—— 空数组表示不分组
|
|
335
|
+
DataSet ds3 = ds.groupBy()
|
|
336
|
+
.sum("kdcd_init_budget")
|
|
337
|
+
.sum("kdcd_adj_budget")
|
|
338
|
+
.sum("kdcd_actual_amt")
|
|
339
|
+
.finish();
|
|
340
|
+
|
|
341
|
+
// 3.4 分组 + 求和 + 指定别名(给聚合结果重命名)
|
|
342
|
+
// sum("原始值", "别名") —— 当需要把 0 作为初始值求和时
|
|
343
|
+
DataSet ds4 = ds.groupBy(new String[]{"kdcd_project"})
|
|
344
|
+
.sum("0", "kdcd_init_budget") // 用0填充,别名为 kdcd_init_budget
|
|
345
|
+
.sum("kdcd_adj_budget") // 保留原字段名
|
|
346
|
+
.sum("kdcd_actual_amt")
|
|
347
|
+
.finish();
|
|
348
|
+
|
|
349
|
+
// 3.5 分组 + 自定义聚合函数(agg)
|
|
350
|
+
// agg(自定义聚合函数, 参数字段, 输出别名)
|
|
351
|
+
DataSet ds5 = ds.groupBy(new String[]{"kdcd_project"})
|
|
352
|
+
.agg(new GroupMaxFunction(), "kdcd_version_number", "max_version")
|
|
353
|
+
.finish();
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// -------------------- 4. join 数据集关联 --------------------
|
|
357
|
+
private void joinExamples(DataSet dsA, DataSet dsB) {
|
|
358
|
+
// 4.1 LEFT JOIN + 单条件关联
|
|
359
|
+
DataSet ds1 = dsA.leftJoin(dsB)
|
|
360
|
+
.on("kdcd_project", "kdcd_project")
|
|
361
|
+
.select("kdcd_project", "project_name", "budget_amt", "actual_amt")
|
|
362
|
+
.finish();
|
|
363
|
+
|
|
364
|
+
// 4.2 LEFT JOIN + 多条件关联(链式 on)
|
|
365
|
+
DataSet ds2 = dsA.leftJoin(dsB)
|
|
366
|
+
.on("kdcd_project", "kdcd_project")
|
|
367
|
+
.on("max_version", "kdcd_version_number") // 第二个关联条件
|
|
368
|
+
.select("kdcd_type", "kdcd_expense", "kdcd_init_budget", "kdcd_adj_budget")
|
|
369
|
+
.finish();
|
|
370
|
+
|
|
371
|
+
// 4.3 INNER JOIN(join 而非 leftJoin)
|
|
372
|
+
DataSet ds3 = dsA.join(dsB)
|
|
373
|
+
.on("kdcd_project", "kdcd_project")
|
|
374
|
+
.on("max_version", "kdcd_version_number")
|
|
375
|
+
.select("kdcd_budget_item", "kdcd_init_budget", "kdcd_adj_budget", "kdcd_actual_amt")
|
|
376
|
+
.finish();
|
|
377
|
+
|
|
378
|
+
// 4.4 JOIN 选择两边的字段:左表字段 + 右表字段
|
|
379
|
+
DataSet ds4 = dsA.leftJoin(dsB)
|
|
380
|
+
.on("realcard", "realcardid")
|
|
381
|
+
.on("period", "period")
|
|
382
|
+
.select(AlgoUtils.fieldsOf(dsA), // 左表所有字段
|
|
383
|
+
new String[]{"kdcd_zhejiu", "kdcd_kuanian"}) // 右表指定字段
|
|
384
|
+
.finish();
|
|
385
|
+
|
|
386
|
+
// 4.5 JOIN 后再接其他操作
|
|
387
|
+
DataSet ds5 = dsA.leftJoin(dsB)
|
|
388
|
+
.on("kdcd_measureperiod", "kdcd_measureperiod")
|
|
389
|
+
.on("kdcd_contract.id", "kdcd_contract.id")
|
|
390
|
+
.select("kdcd_contract.id", "kdcd_sum", "kdcd_measureperiodnum")
|
|
391
|
+
.finish()
|
|
392
|
+
.distinct(); // JOIN 后去重
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// -------------------- 5. union 数据集合并 --------------------
|
|
396
|
+
private void unionExamples(DataSet ds1, DataSet ds2, DataSet ds3, DataSet ds4, DataSet ds5) {
|
|
397
|
+
// 5.1 两个 DataSet 合并
|
|
398
|
+
DataSet union1 = ds1.union(ds2);
|
|
399
|
+
|
|
400
|
+
// 5.2 多个 DataSet 一次性合并(可变参数)
|
|
401
|
+
DataSet union2 = ds1.union(ds2, ds3, ds4, ds5);
|
|
402
|
+
|
|
403
|
+
// 5.3 链式合并
|
|
404
|
+
DataSet union3 = ds1.union(ds2).copy() // 注意: union 后需 copy() 才能再次 union
|
|
405
|
+
.union(ds3).copy()
|
|
406
|
+
.union(ds4);
|
|
407
|
+
|
|
408
|
+
// 5.4 合并后再聚合(先 union 再 groupBy)
|
|
409
|
+
DataSet union4 = ds1.union(ds2)
|
|
410
|
+
.groupBy(new String[]{"kdcd_budget_item"})
|
|
411
|
+
.sum("kdcd_init_budget")
|
|
412
|
+
.sum("kdcd_adj_budget")
|
|
413
|
+
.sum("kdcd_actual_amt")
|
|
414
|
+
.finish();
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// -------------------- 6. addField / addNullField 添加字段 --------------------
|
|
418
|
+
private void addFieldExamples(DataSet ds) {
|
|
419
|
+
// 6.1 添加常量字段(排序用)
|
|
420
|
+
DataSet ds1 = ds.addField("5", "kdcd_sort");
|
|
421
|
+
|
|
422
|
+
// 6.2 添加表达式计算字段
|
|
423
|
+
DataSet ds2 = ds.addField("budget_amt - actual_amt", "diff_amt");
|
|
424
|
+
|
|
425
|
+
// 6.3 添加字符串常量作为来源标记
|
|
426
|
+
DataSet ds3 = ds.addField("'计量明细'", "kdcd_source");
|
|
427
|
+
|
|
428
|
+
// 6.4 添加空值字段(当某些分录缺少某字段时补 null)
|
|
429
|
+
DataSet ds4 = ds.addNullField("kdcd_item_sort")
|
|
430
|
+
.addNullField("kdcd_item_content")
|
|
431
|
+
.addField("'预付款'", "kdcd_source");
|
|
432
|
+
|
|
433
|
+
// 6.5 链式添加多个字段
|
|
434
|
+
DataSet ds5 = ds.addField("1", "summarytype")
|
|
435
|
+
.addNullField("currency");
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// -------------------- 7. orderBy / distinct / removeFields --------------------
|
|
439
|
+
private void orderDistinctExamples(DataSet ds) {
|
|
440
|
+
// 7.1 单字段排序
|
|
441
|
+
DataSet ds1 = ds.orderBy(new String[]{"project_name"});
|
|
442
|
+
|
|
443
|
+
// 7.2 多字段排序
|
|
444
|
+
DataSet ds2 = ds.orderBy(new String[]{"kdcd_settleorg", "kdcd_billno", "kdcd_currentaccount", "kdcd_source"});
|
|
445
|
+
|
|
446
|
+
// 7.3 去重
|
|
447
|
+
DataSet ds3 = ds.distinct();
|
|
448
|
+
|
|
449
|
+
// 7.4 排序 + 去重组合
|
|
450
|
+
DataSet ds4 = ds.distinct().orderBy(new String[]{"kdcd_sort"});
|
|
451
|
+
|
|
452
|
+
// 7.5 移除不需要的字段
|
|
453
|
+
DataSet ds5 = ds.removeFields("kdcd_measureperiodnum");
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// -------------------- 8. map 自定义行映射 --------------------
|
|
457
|
+
private void mapExamples(DataSet ds) {
|
|
458
|
+
// 自定义 MapFunction 实现行级转换(如为报表行添加序号)
|
|
459
|
+
//
|
|
460
|
+
// 使用方式:
|
|
461
|
+
// CustomRowMapper mapper = new CustomRowMapper(ds.getRowMeta());
|
|
462
|
+
// DataSet result = ds.map(mapper);
|
|
463
|
+
//
|
|
464
|
+
// MapFunction 实现模板:
|
|
465
|
+
// public class CustomRowMapper extends MapFunction {
|
|
466
|
+
// private RowMeta rowMeta;
|
|
467
|
+
// public CustomRowMapper(RowMeta sourceMeta) {
|
|
468
|
+
// this.rowMeta = new RowMeta(sourceMeta.getFields());
|
|
469
|
+
// }
|
|
470
|
+
// @Override
|
|
471
|
+
// public Object[] map(Row row) {
|
|
472
|
+
// Object[] newRow = new Object[rowMeta.getFieldCount()];
|
|
473
|
+
// for (int i = 0; i < rowMeta.getFieldCount(); i++) {
|
|
474
|
+
// newRow[i] = row.get(i);
|
|
475
|
+
// }
|
|
476
|
+
// newRow[0] = "自定义值"; // 修改指定字段
|
|
477
|
+
// return newRow;
|
|
478
|
+
// }
|
|
479
|
+
// @Override
|
|
480
|
+
// public RowMeta getResultRowMeta() { return rowMeta; }
|
|
481
|
+
// }
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// -------------------- 9. copy 克隆与复用 --------------------
|
|
485
|
+
private void copyExamples(DataSet ds) {
|
|
486
|
+
// 重要:DataSet 被迭代器访问或循环遍历后会自动关闭,关闭后无法再做任何数据集操作!
|
|
487
|
+
// 典型场景:
|
|
488
|
+
// for (Row row : ds) { ... } ← 循环结束后 ds 已关闭
|
|
489
|
+
// ds.select(...) / ds.filter(...) / ds.groupBy(...) ← 全部报错
|
|
490
|
+
// 因此:如果迭代后还需要继续操作,必须在迭代前先 copy()。
|
|
491
|
+
// 同理:一个 DataSet 做多次不同处理时,也必须先 copy() 再分别操作。
|
|
492
|
+
|
|
493
|
+
// 9.1 同一数据集做不同过滤
|
|
494
|
+
DataSet version1 = ds.copy().filter("billstatus = 'C' and kdcd_version_number = 1.0"); // 第一版
|
|
495
|
+
DataSet latestVersion = ds.copy().groupBy(new String[]{"kdcd_project"}) // 最新版
|
|
496
|
+
.agg(new GroupMaxFunction(), "kdcd_version_number", "maxversion")
|
|
497
|
+
.finish();
|
|
498
|
+
|
|
499
|
+
// 9.2 copy 后做不同聚合
|
|
500
|
+
DataSet totalDirect = ds.copy().groupBy().sum("kdcd_init_budget").sum("kdcd_adj_budget").finish();
|
|
501
|
+
DataSet detailRows = ds.copy().select("kdcd_budget_item", "kdcd_init_budget", "kdcd_adj_budget");
|
|
502
|
+
|
|
503
|
+
// 9.3 union 后需要 copy 才能继续 union
|
|
504
|
+
DataSet result = ds.copy().union(version1).copy().union(latestVersion);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// -------------------- 10. DataSet ↔ DynamicObject 互转 --------------------
|
|
508
|
+
private void conversionExamples(DataSet ds) {
|
|
509
|
+
// 10.1 DataSet → DynamicObjectCollection(使用 DynamicObjectUtils.fromDataSet 封装)
|
|
510
|
+
DynamicObjectCollection dynColl = DynamicObjectUtils.fromDataSet(ds);
|
|
511
|
+
for (DynamicObject row : dynColl) {
|
|
512
|
+
String number = row.getString("accountNumber");
|
|
513
|
+
BigDecimal amount = row.getBigDecimal("kdcd_actual_amt");
|
|
514
|
+
// ... 做复杂的对象级操作
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// 10.2 获取 DataSet 中某列的所有值 —— 使用 AlgoUtils 一行搞定
|
|
518
|
+
Set<Long> idSet = AlgoUtils.setOf(ds.copy(), "id"); // 提取为 Set
|
|
519
|
+
List<Long> idList = AlgoUtils.listOf(ds.copy(), "id"); // 提取为 List
|
|
520
|
+
|
|
521
|
+
// 10.3 DataSet Stream 支持 —— 使用 AlgoUtils.stream()
|
|
522
|
+
Set<String> numberSet = AlgoUtils.stream(ds.copy())
|
|
523
|
+
.map(row -> row.getString("number"))
|
|
524
|
+
.collect(Collectors.toSet());
|
|
525
|
+
|
|
526
|
+
// 10.4 DataSet 单列求和 —— 使用 AlgoUtils.sumOf()
|
|
527
|
+
BigDecimal totalAmt = AlgoUtils.sumOf(ds.copy(), "kdcd_amount");
|
|
528
|
+
|
|
529
|
+
// 10.5 DynamicObjectCollection → DataSet
|
|
530
|
+
DynamicObjectCollection sourceColl = new DynamicObjectCollection();
|
|
531
|
+
DataSet fromColl = DynamicObjectUtils.toDataSet(sourceColl); // 全字段
|
|
532
|
+
DataSet fromCollPartial = DynamicObjectUtils.toDataSet(sourceColl, "id", "name"); // 选择字段
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// -------------------- 11. 原生 SQL 查询 --------------------
|
|
536
|
+
private void rawSqlExamples() {
|
|
537
|
+
// 11.1 通过 DB.queryDataSet 执行原生SQL(复杂跨表场景)
|
|
538
|
+
String sql = "/*dialect*/ SELECT fnumber, fname FROM t_meta_formdesign_l WHERE flocaleid = 'zh_CN'";
|
|
539
|
+
DataSet ds1 = DB.queryDataSet(getClass().getName(), DBRoute.of("sys.meta"), sql);
|
|
540
|
+
|
|
541
|
+
// 11.2 带参数的SQL(使用 SqlBuilder)
|
|
542
|
+
// SqlBuilder sqlBuilder = new SqlBuilder();
|
|
543
|
+
// sqlBuilder.append("select fentryid, frealcardid from t_fa_depredetailentry where forgid = ?", orgId);
|
|
544
|
+
// DataSet ds2 = DB.queryDataSet(getClass().getName(), DBRoute.of("fa"), sqlBuilder);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// -------------------- 12. getRowMeta 元数据操作 --------------------
|
|
548
|
+
private void rowMetaExamples(DataSet ds) {
|
|
549
|
+
// 12.1 获取 DataSet 的所有字段名(使用 AlgoUtils.fieldsOf 封装)
|
|
550
|
+
String[] fieldNames = AlgoUtils.fieldsOf(ds);
|
|
551
|
+
|
|
552
|
+
// 12.2 获取字段详细信息
|
|
553
|
+
RowMeta rowMeta = ds.getRowMeta();
|
|
554
|
+
Field[] fields = rowMeta.getFields();
|
|
555
|
+
for (Field field : fields) {
|
|
556
|
+
String name = field.getName(); // 字段名
|
|
557
|
+
String alias = field.getAlias(); // 别名
|
|
558
|
+
DataType type = field.getDataType(); // 数据类型
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// 12.3 基于现有 DataSet 的 RowMeta 动态添加空字段
|
|
562
|
+
DataSet sumDs = ds.copy().groupBy().sum("monthdepre").finish();
|
|
563
|
+
Set<String> allFields = new java.util.LinkedHashSet<>();
|
|
564
|
+
for (Field field : ds.getRowMeta().getFields()) {
|
|
565
|
+
allFields.add(field.getAlias().toLowerCase());
|
|
566
|
+
}
|
|
567
|
+
for (String field : allFields) {
|
|
568
|
+
if (!"monthdepre".equalsIgnoreCase(field)) {
|
|
569
|
+
sumDs = sumDs.addNullField(field); // 汇总行补全其他字段为null
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
sumDs = sumDs.select(allFields.toArray(new String[0])); // 对齐字段顺序
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// ===================================================================
|
|
576
|
+
// 自定义聚合函数示例 —— GroupMaxFunction
|
|
577
|
+
// ===================================================================
|
|
578
|
+
/**
|
|
579
|
+
* 自定义聚合函数:求分组内的最大值。
|
|
580
|
+
* <pre>
|
|
581
|
+
* 使用方式:
|
|
582
|
+
* DataSet maxResult = ds.groupBy(new String[]{"kdcd_project"})
|
|
583
|
+
* .agg(new GroupMaxFunction(), "kdcd_version_number", "max_version")
|
|
584
|
+
* .finish();
|
|
585
|
+
* </pre>
|
|
586
|
+
*/
|
|
587
|
+
static class GroupMaxFunction extends CustomAggFunction<BigDecimal> {
|
|
588
|
+
public GroupMaxFunction() {
|
|
589
|
+
super("group_max", DataType.BigDecimalType);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/** 初始聚合值 */
|
|
593
|
+
@Override
|
|
594
|
+
public BigDecimal newAggValue() {
|
|
595
|
+
return BigDecimal.ZERO;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/** 遍历每一行,取当前值与已有最大值中较大的 */
|
|
599
|
+
@Override
|
|
600
|
+
public BigDecimal addValue(BigDecimal oldValue, Object newValue) {
|
|
601
|
+
BigDecimal current = new BigDecimal(newValue.toString());
|
|
602
|
+
return oldValue.max(current);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/** 分批处理时,合并不同批次的结果 */
|
|
606
|
+
@Override
|
|
607
|
+
public BigDecimal combineAggValue(BigDecimal v1, BigDecimal v2) {
|
|
608
|
+
return v1.max(v2);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
@Override
|
|
612
|
+
public Object getResult(BigDecimal result) {
|
|
613
|
+
return result;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Snippets 分层说明
|
|
2
|
+
|
|
3
|
+
`assets/snippets` 里的样例按“如何选代码”分成两层。从决策矩阵命中插件类型后,可直接在下表中查找对应 snippet。
|
|
4
|
+
|
|
5
|
+
> 完整插件选型与能力矩阵见 [rules/decision-matrix.md](../../rules/decision-matrix.md)。
|
|
6
|
+
|
|
7
|
+
## 第一层:推荐写法
|
|
8
|
+
|
|
9
|
+
- 默认先读这一层。
|
|
10
|
+
- 这层代表当前 `ok-cosmic` 推荐的实现路径:优先走 commons 封装、`*Ext` 基类、团队认可的默认写法。
|
|
11
|
+
- 即使内部仍包含少量 BOS 原生 API,也表示“这是当前 skill 默认推荐的落地方式”,不是让模型先去拼底层样板。
|
|
12
|
+
|
|
13
|
+
| 场景关键词 | snippet 文件 |
|
|
14
|
+
|---|---|
|
|
15
|
+
| 字段取值/赋值/getValue/setValue | [GetAndSetValueSample.java](form/GetAndSetValueSample.java) |
|
|
16
|
+
| 页面状态/锁定/可见/刷新/关闭/pageCache | [ViewControlOpsSample.java](form/ViewControlOpsSample.java) |
|
|
17
|
+
| 分录行计算/汇总/金额联动 | [EntryRowCalculateSample.java](form/EntryRowCalculateSample.java) |
|
|
18
|
+
| 确认框/二次确认/ConfirmCallBack | [ConfirmDialogSample.java](form/ConfirmDialogSample.java) |
|
|
19
|
+
| 操作前拦截确认/beforeDoOperation | [BeforeOperationConfirmSample.java](form/BeforeOperationConfirmSample.java) |
|
|
20
|
+
| F7 过滤/基础资料弹窗过滤 | [F7FilterSample.java](form/F7FilterSample.java) |
|
|
21
|
+
| 打开单据弹窗/showForm/Modal | [OpenBillModalSample.java](form/OpenBillModalSample.java) |
|
|
22
|
+
| 子页面回传数据/closedCallBack | [ReturnParentDataSample.java](form/ReturnParentDataSample.java) |
|
|
23
|
+
| 超链接跳转/分录+列表 | [HyperlinkJumpSample.java](form/HyperlinkJumpSample.java) |
|
|
24
|
+
| 列表插件基础/选中行/批量操作 | [ListPluginBasicSample.java](list/ListPluginBasicSample.java) |
|
|
25
|
+
| 操作校验器/addValidators | [OpAddValidatorsSample.java](operation/OpAddValidatorsSample.java) |
|
|
26
|
+
| 操作参数传递/OperateOption/操作提示 | [OperationOptionBridgeSample.java](operation/OperationOptionBridgeSample.java) |
|
|
27
|
+
| 下推/选单/来源追踪/BotpUtils | [BotpTracePushSample.java](botp/BotpTracePushSample.java) |
|
|
28
|
+
| 批量查询样本/分组映射/批量反写/最近值恢复 | [BatchQuerySample.java](query/BatchQuerySample.java) |
|
|
29
|
+
| 查询/聚合/DataSet/统计 | [DataSetQueryStatSample.java](query/DataSetQueryStatSample.java) |
|
|
30
|
+
| 报表界面插件/校验/超链接/行加工 | [SampleReportFormPlugin.java](report/SampleReportFormPlugin.java) |
|
|
31
|
+
| 报表取数/DataSet Cookbook/动态列 | [SampleReportListDataPlugin.java](report/SampleReportListDataPlugin.java) |
|
|
32
|
+
| 基础资料查询/loadFromCache | [BaseDataQuerySample.java](query/BaseDataQuerySample.java) |
|
|
33
|
+
| DynamicObject 操作/安全取值 | [DynamicObjectOpsSample.java](data/DynamicObjectOpsSample.java) |
|
|
34
|
+
| 后端建单/保存/查询/复制 | [DynamicObjectCrudSample.java](data/DynamicObjectCrudSample.java) |
|
|
35
|
+
| 附件上传/绑定/AttachmentUtils | [AttachmentUploadBindSample.java](attachment/AttachmentUploadBindSample.java) |
|
|
36
|
+
| 线程池批量处理/并发任务/优雅关闭 | [SampleThreadPoolBatch.java](concurrent/SampleThreadPoolBatch.java) |
|
|
37
|
+
| 缓存/AppCache/分布式缓存/loadFromCache | [SampleCacheUsage.java](cache/SampleCacheUsage.java) |
|
|
38
|
+
|
|
39
|
+
## 第二层:原生兜底
|
|
40
|
+
|
|
41
|
+
- 只有在第一层没有覆盖,或者场景本身就是控件底层能力 / 原生 BOS 事件时,再读这一层。
|
|
42
|
+
- 这层通常意味着:
|
|
43
|
+
- 当前仓库暂无更高层封装;
|
|
44
|
+
- 该场景更偏原生事件、控件 API、平台服务;
|
|
45
|
+
- 写代码前更应该配合 `references/base/*` 和脚本校验一起使用。
|
|
46
|
+
|
|
47
|
+
| 场景关键词 | snippet 文件 |
|
|
48
|
+
|---|---|
|
|
49
|
+
| 树形控件/TreeView/树节点 | [TreeControlSample.java](form/TreeControlSample.java) |
|
|
50
|
+
| 列表预打开过滤/setFilter/preOpenForm | [ListPreOpenFilterSample.java](list/ListPreOpenFilterSample.java) |
|
|
51
|
+
| 消息通知/邮件/MessageService | [MessageNotifySample.java](message/MessageNotifySample.java) |
|
|
52
|
+
| 后台调度任务/定时任务 | [ScheduleTaskSample.java](task/ScheduleTaskSample.java) |
|
|
53
|
+
| MQ消费者/分布式锁防重/MessageAcker | [SampleMQConsumer.java](mq/SampleMQConsumer.java) |
|
|
54
|
+
| 工作流插件/审批参与人/流程通知/条件分支 | [SampleWorkflowPlugin.java](workflow/SampleWorkflowPlugin.java) |
|
|
55
|
+
|
|
56
|
+
## 选择规则
|
|
57
|
+
|
|
58
|
+
1. 同一主题如果第一层已经有样例,不要直接跳到第二层。
|
|
59
|
+
2. 第二层代码可以用,但默认不应反向覆盖第一层的团队写法。
|
|
60
|
+
3. 单个 snippet 头部的 4 行元信息优先作为快速判断依据:
|
|
61
|
+
- `适用插件`
|
|
62
|
+
- `优先封装`
|
|
63
|
+
- `原生兜底`
|
|
64
|
+
- `相关 lint 规则`
|