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,508 @@
|
|
|
1
|
+
# 表单插件场景检查表
|
|
2
|
+
|
|
3
|
+
## 🔴 P0 级问题
|
|
4
|
+
|
|
5
|
+
### 1. propertyChanged 循环触发
|
|
6
|
+
**检查点**:
|
|
7
|
+
- `propertyChanged` 中是否存在 A 字段改 B、B 字段改 A 的循环联动?
|
|
8
|
+
- 批量 `setValue` 是否未用 `beginInit/endInit` 包裹导致递归触发?
|
|
9
|
+
|
|
10
|
+
**风险**: 无限递归导致栈溢出或界面卡死
|
|
11
|
+
|
|
12
|
+
**修正方案**:
|
|
13
|
+
```java
|
|
14
|
+
// ❌ 错误写法 - 循环触发
|
|
15
|
+
@Override
|
|
16
|
+
public void propertyChanged(PropertyChangedArgs e) {
|
|
17
|
+
String key = e.getProperty().getName();
|
|
18
|
+
if ("fieldA".equals(key)) {
|
|
19
|
+
getModel().setValue("fieldB", newValue); // 触发 fieldB 的 propertyChanged
|
|
20
|
+
}
|
|
21
|
+
if ("fieldB".equals(key)) {
|
|
22
|
+
getModel().setValue("fieldA", newValue); // 又触发 fieldA,死循环!
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ✅ 正确写法 - 使用 beginInit 避免递归
|
|
27
|
+
@Override
|
|
28
|
+
public void propertyChanged(PropertyChangedArgs e) {
|
|
29
|
+
String key = e.getProperty().getName();
|
|
30
|
+
if ("fieldA".equals(key)) {
|
|
31
|
+
getModel().beginInit();
|
|
32
|
+
try {
|
|
33
|
+
getModel().setValue("fieldB", newValue);
|
|
34
|
+
getModel().setValue("fieldC", newValue2);
|
|
35
|
+
} finally {
|
|
36
|
+
getModel().endInit();
|
|
37
|
+
}
|
|
38
|
+
getView().updateView("fieldB");
|
|
39
|
+
getView().updateView("fieldC");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
### 2. beforeDoOperation 校验失败未 setCancel
|
|
47
|
+
**检查点**:
|
|
48
|
+
- `beforeDoOperation` 中校验不通过时是否调用了 `args.setCancel(true)`?
|
|
49
|
+
- 是否只显示了提示但未取消操作?
|
|
50
|
+
|
|
51
|
+
**风险**: 校验失败但操作仍然继续执行,数据被错误保存
|
|
52
|
+
|
|
53
|
+
**修正方案**:
|
|
54
|
+
```java
|
|
55
|
+
// ❌ 错误写法 - 校验失败但未取消操作
|
|
56
|
+
@Override
|
|
57
|
+
public void beforeDoOperation(BeforeDoOperationEventArgs args) {
|
|
58
|
+
super.beforeDoOperation(args);
|
|
59
|
+
if (getModel().getValue("requiredField") == null) {
|
|
60
|
+
getView().showTipNotification("字段不能为空");
|
|
61
|
+
// 缺少 args.setCancel(true),操作仍会继续!
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ✅ 正确写法
|
|
66
|
+
@Override
|
|
67
|
+
public void beforeDoOperation(BeforeDoOperationEventArgs args) {
|
|
68
|
+
super.beforeDoOperation(args);
|
|
69
|
+
FormOperate formOperate = (FormOperate) args.getSource();
|
|
70
|
+
if ("save".equals(formOperate.getOperateKey())) {
|
|
71
|
+
if (getModel().getValue("requiredField") == null) {
|
|
72
|
+
args.setCancel(true);
|
|
73
|
+
getView().showTipNotification("字段不能为空");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
### 3. 交互式操作未检查回调标识(死循环)
|
|
83
|
+
**检查点**:
|
|
84
|
+
- 操作插件中抛出 `KDInteractionException` 前是否先检查了交互确认结果?
|
|
85
|
+
- 交互标识(sponsor)是否唯一且固定?
|
|
86
|
+
|
|
87
|
+
**风险**: 用户确认后再次进入操作,再次抛出交互异常,形成死循环
|
|
88
|
+
|
|
89
|
+
**修正方案**:
|
|
90
|
+
```java
|
|
91
|
+
// ❌ 错误写法 - 未检查回调,死循环
|
|
92
|
+
@Override
|
|
93
|
+
public void beforeExecuteOperationTransaction(BeforeOperationArgs e) {
|
|
94
|
+
InteractionContext ctx = new InteractionContext();
|
|
95
|
+
ctx.setSimpleMessage("确认继续?");
|
|
96
|
+
throw new KDInteractionException("sponsor", ctx); // 每次都抛,死循环!
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ✅ 正确写法 - 先检查是否为回调
|
|
100
|
+
private static final String INTERACTION_SPONSOR = "com.xxx.MyPlugin";
|
|
101
|
+
|
|
102
|
+
@Override
|
|
103
|
+
public void beforeExecuteOperationTransaction(BeforeOperationArgs e) {
|
|
104
|
+
String confirmStr = this.getOption().getVariableValue(
|
|
105
|
+
OperateOptionConst.INTERACTIONCONFIRMRESULT, "");
|
|
106
|
+
InteractionConfirmResult confirmResult = InteractionConfirmResult.fromJsonString(confirmStr);
|
|
107
|
+
if (confirmResult.getResults().containsKey(INTERACTION_SPONSOR)) {
|
|
108
|
+
// 已经是回调,根据用户选择处理
|
|
109
|
+
MessageBoxResult result = MessageBoxResult.valueOf(
|
|
110
|
+
confirmResult.getResults().get(INTERACTION_SPONSOR));
|
|
111
|
+
if (result == MessageBoxResult.Yes) {
|
|
112
|
+
return; // 用户确认,继续执行
|
|
113
|
+
} else {
|
|
114
|
+
e.cancel = true;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// 首次进入,抛出交互
|
|
119
|
+
InteractionContext ctx = new InteractionContext();
|
|
120
|
+
ctx.setSimpleMessage("确认继续?");
|
|
121
|
+
throw new KDInteractionException(INTERACTION_SPONSOR, ctx);
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 🟠 P1 级问题
|
|
128
|
+
|
|
129
|
+
### 4. registerListener 未调用 super
|
|
130
|
+
**检查点**:
|
|
131
|
+
- `registerListener` 方法是否调用了 `super.registerListener(e)`?
|
|
132
|
+
- 其他生命周期方法(`afterBindData`、`propertyChanged` 等)是否调用了 super?
|
|
133
|
+
|
|
134
|
+
**风险**: 框架默认行为被跳过,可能导致其他插件的监听器失效
|
|
135
|
+
|
|
136
|
+
**修正方案**:
|
|
137
|
+
```java
|
|
138
|
+
// ❌ 错误写法
|
|
139
|
+
@Override
|
|
140
|
+
public void registerListener(EventObject e) {
|
|
141
|
+
addItemClickListeners("tbmain"); // 缺少 super 调用
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ✅ 正确写法
|
|
145
|
+
@Override
|
|
146
|
+
public void registerListener(EventObject e) {
|
|
147
|
+
super.registerListener(e);
|
|
148
|
+
addItemClickListeners("tbmain");
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
### 5. F7 监听未注册
|
|
155
|
+
**检查点**:
|
|
156
|
+
- 使用 `beforeF7Select` / `afterF7Select` 事件但未在 `registerListener` 中注册监听?
|
|
157
|
+
- 插件类是否实现了 `BeforeF7SelectListener` / `AfterF7SelectListener` 接口?
|
|
158
|
+
|
|
159
|
+
**风险**: F7 事件不触发,过滤条件不生效
|
|
160
|
+
|
|
161
|
+
**修正方案**:
|
|
162
|
+
```java
|
|
163
|
+
// ❌ 错误写法 - 未注册监听
|
|
164
|
+
public class MyPlugin extends AbstractFormPlugin implements BeforeF7SelectListener {
|
|
165
|
+
@Override
|
|
166
|
+
public void beforeF7Select(BeforeF7SelectEvent e) {
|
|
167
|
+
// 永远不会被调用!
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ✅ 正确写法 - 在 registerListener 中注册
|
|
172
|
+
public class MyPlugin extends AbstractFormPlugin implements BeforeF7SelectListener {
|
|
173
|
+
@Override
|
|
174
|
+
public void registerListener(EventObject e) {
|
|
175
|
+
super.registerListener(e);
|
|
176
|
+
BasedataEdit f7 = (BasedataEdit) getControl("fieldName");
|
|
177
|
+
if (f7 != null) {
|
|
178
|
+
f7.addBeforeF7SelectListener(this);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
@Override
|
|
183
|
+
public void beforeF7Select(BeforeF7SelectEvent e) {
|
|
184
|
+
// 正确触发
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
### 6. 分录字段操作未传 rowIndex
|
|
192
|
+
**检查点**:
|
|
193
|
+
- `propertyChanged` 中操作分录字段时是否通过 `e.getChangeSet()[0].getRowIndex()` 获取行号?
|
|
194
|
+
- `setValue` 分录字段时是否传入了 rowIndex 参数?
|
|
195
|
+
|
|
196
|
+
**风险**: 修改了错误行的数据,或修改了所有行
|
|
197
|
+
|
|
198
|
+
**修正方案**:
|
|
199
|
+
```java
|
|
200
|
+
// ❌ 错误写法 - 分录字段未传 rowIndex
|
|
201
|
+
@Override
|
|
202
|
+
public void propertyChanged(PropertyChangedArgs e) {
|
|
203
|
+
if ("material".equals(e.getProperty().getName())) {
|
|
204
|
+
DynamicObject material = (DynamicObject) getModel().getValue("material");
|
|
205
|
+
getModel().setValue("relatedField", material.get("name")); // 缺少 rowIndex!
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ✅ 正确写法
|
|
210
|
+
@Override
|
|
211
|
+
public void propertyChanged(PropertyChangedArgs e) {
|
|
212
|
+
if ("material".equals(e.getProperty().getName())) {
|
|
213
|
+
int rowIndex = e.getChangeSet()[0].getRowIndex();
|
|
214
|
+
DynamicObject material = (DynamicObject) getModel().getValue("material", rowIndex);
|
|
215
|
+
if (material != null) {
|
|
216
|
+
getModel().setValue("relatedField", material.get("name"), rowIndex);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
### 7. closedCallBack 未校验 actionId
|
|
225
|
+
**检查点**:
|
|
226
|
+
- `closedCallBack` 中是否根据 `e.getActionId()` 区分不同弹窗的回调?
|
|
227
|
+
- 是否直接处理 `returnData` 而未判断来源?
|
|
228
|
+
|
|
229
|
+
**风险**: 多个弹窗的回调混淆,数据被错误处理
|
|
230
|
+
|
|
231
|
+
**修正方案**:
|
|
232
|
+
```java
|
|
233
|
+
// ❌ 错误写法 - 未区分回调来源
|
|
234
|
+
@Override
|
|
235
|
+
public void closedCallBack(ClosedCallBackEvent e) {
|
|
236
|
+
Object data = e.getReturnData();
|
|
237
|
+
getModel().setValue("field", data); // 不知道是哪个弹窗返回的!
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ✅ 正确写法
|
|
241
|
+
@Override
|
|
242
|
+
public void closedCallBack(ClosedCallBackEvent e) {
|
|
243
|
+
if ("selectCallback".equals(e.getActionId())) {
|
|
244
|
+
Object data = e.getReturnData();
|
|
245
|
+
if (data != null) {
|
|
246
|
+
getModel().setValue("field", data);
|
|
247
|
+
getView().updateView("field");
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
### 8. 字符串比较方式不安全
|
|
256
|
+
**检查点**:
|
|
257
|
+
- 是否使用 `variable.equals("constant")` 而非 `"constant".equals(variable)`?
|
|
258
|
+
- `getItemKey()` / `getOperateKey()` 返回值是否可能为 null?
|
|
259
|
+
|
|
260
|
+
**风险**: 变量为 null 时抛出 NullPointerException
|
|
261
|
+
|
|
262
|
+
**修正方案**:
|
|
263
|
+
```java
|
|
264
|
+
// ❌ 错误写法 - 变量在前,可能 NPE
|
|
265
|
+
if (evt.getItemKey().equals("btnSave")) { ... }
|
|
266
|
+
|
|
267
|
+
// ✅ 正确写法 - 常量在前
|
|
268
|
+
if ("btnSave".equals(evt.getItemKey())) { ... }
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 🟡 P2 级问题
|
|
274
|
+
|
|
275
|
+
### 9. FormShowParameter 参数不可序列化
|
|
276
|
+
**检查点**:
|
|
277
|
+
- `getCustomParams().put()` 传递的值是否可序列化?
|
|
278
|
+
- 是否传递了 DynamicObject 等不可序列化的复杂对象?
|
|
279
|
+
|
|
280
|
+
**风险**: 序列化失败导致弹窗打开异常
|
|
281
|
+
|
|
282
|
+
**修正方案**:
|
|
283
|
+
```java
|
|
284
|
+
// ❌ 错误写法 - 传递不可序列化对象
|
|
285
|
+
param.getCustomParams().put("data", dynamicObject);
|
|
286
|
+
|
|
287
|
+
// ✅ 正确写法 - 只传基本类型或 String
|
|
288
|
+
param.getCustomParams().put("dataId", dynamicObject.getLong("id"));
|
|
289
|
+
param.getCustomParams().put("dataName", dynamicObject.getString("name"));
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
### 10. PageCache 值类型限制
|
|
295
|
+
**检查点**:
|
|
296
|
+
- `getPageCache().put()` 的值是否为 String 类型?
|
|
297
|
+
- 复杂对象是否先序列化为 JSON 再存入?
|
|
298
|
+
|
|
299
|
+
**风险**: 非 String 类型存入 PageCache 可能导致类型转换异常
|
|
300
|
+
|
|
301
|
+
**修正方案**:
|
|
302
|
+
```java
|
|
303
|
+
// ❌ 错误写法 - 存入非 String 类型
|
|
304
|
+
getPageCache().put("ids", idList);
|
|
305
|
+
|
|
306
|
+
// ✅ 正确写法 - 序列化后存入
|
|
307
|
+
getPageCache().put("ids", SerializationUtils.toJsonString(idList));
|
|
308
|
+
// 读取时反序列化
|
|
309
|
+
String idsJson = getPageCache().get("ids");
|
|
310
|
+
List<Long> ids = SerializationUtils.fromJsonString(idsJson, List.class);
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
### 11. 列表 setFilter 未调用 super
|
|
316
|
+
**检查点**:
|
|
317
|
+
- 列表插件 `setFilter` 方法是否调用了 `super.setFilter(e)`?
|
|
318
|
+
|
|
319
|
+
**风险**: 框架默认过滤逻辑被跳过,可能导致数据权限失效
|
|
320
|
+
|
|
321
|
+
**修正方案**:
|
|
322
|
+
```java
|
|
323
|
+
// ❌ 错误写法
|
|
324
|
+
@Override
|
|
325
|
+
public void setFilter(SetFilterEvent e) {
|
|
326
|
+
e.getQFilters().add(new QFilter("status", QCP.equals, "A"));
|
|
327
|
+
// 缺少 super 调用
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// ✅ 正确写法
|
|
331
|
+
@Override
|
|
332
|
+
public void setFilter(SetFilterEvent e) {
|
|
333
|
+
super.setFilter(e);
|
|
334
|
+
e.getQFilters().add(new QFilter("status", QCP.equals, "A"));
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
### 12. afterBindData 中 setValue 触发 propertyChanged
|
|
341
|
+
**检查点**:
|
|
342
|
+
- `afterBindData` 中是否直接调用 `getModel().setValue()` 而未使用 `beginInit/endInit` 包裹?
|
|
343
|
+
- 此 setValue 是否会触发 `propertyChanged` 中的联动逻辑导致死循环或数据覆盖?
|
|
344
|
+
|
|
345
|
+
**风险**: afterBindData 触发 propertyChanged,propertyChanged 中的联动逻辑再次修改数据,导致循环或数据错误
|
|
346
|
+
|
|
347
|
+
**修正方案**:
|
|
348
|
+
```java
|
|
349
|
+
// ❌ 错误写法 - afterBindData 中直接 setValue
|
|
350
|
+
@Override
|
|
351
|
+
public void afterBindData(EventObject e) {
|
|
352
|
+
super.afterBindData(e);
|
|
353
|
+
getModel().setValue("calcField", computeValue()); // 触发 propertyChanged
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// ✅ 正确写法 - 使用 beginInit 屏蔽联动
|
|
357
|
+
@Override
|
|
358
|
+
public void afterBindData(EventObject e) {
|
|
359
|
+
super.afterBindData(e);
|
|
360
|
+
getModel().beginInit();
|
|
361
|
+
try {
|
|
362
|
+
getModel().setValue("calcField", computeValue());
|
|
363
|
+
} finally {
|
|
364
|
+
getModel().endInit();
|
|
365
|
+
}
|
|
366
|
+
getView().updateView("calcField");
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
### 13. 分录行删除后仍使用原行号
|
|
373
|
+
**检查点**:
|
|
374
|
+
- `afterDeleteRow` 中是否使用了删除前缓存的行号访问分录数据?
|
|
375
|
+
- 删除行后是否重新获取了行数和行号?
|
|
376
|
+
|
|
377
|
+
**风险**: 删除行后行号偏移,使用旧行号访问到错误数据或数组越界
|
|
378
|
+
|
|
379
|
+
**修正方案**:
|
|
380
|
+
```java
|
|
381
|
+
// ❌ 错误写法 - 删除行后使用原行号
|
|
382
|
+
@Override
|
|
383
|
+
public void afterDeleteRow(AfterDeleteRowEventArgs e) {
|
|
384
|
+
super.afterDeleteRow(e);
|
|
385
|
+
int rowCount = getModel().getEntryRowCount("entryentity");
|
|
386
|
+
for (int i = 0; i < rowCount; i++) {
|
|
387
|
+
// 应重新计算而非依赖删除前的缓存行号
|
|
388
|
+
recalcRow(i);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// ✅ 正确写法 - 基于当前实际行重新遍历
|
|
393
|
+
@Override
|
|
394
|
+
public void afterDeleteRow(AfterDeleteRowEventArgs e) {
|
|
395
|
+
super.afterDeleteRow(e);
|
|
396
|
+
DynamicObjectCollection entries = getModel().getEntryEntity("entryentity");
|
|
397
|
+
getModel().beginInit();
|
|
398
|
+
try {
|
|
399
|
+
for (int i = 0; i < entries.size(); i++) {
|
|
400
|
+
recalcRow(i);
|
|
401
|
+
}
|
|
402
|
+
} finally {
|
|
403
|
+
getModel().endInit();
|
|
404
|
+
}
|
|
405
|
+
getView().updateView("entryentity");
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
### 14. entryRowClick 未校验行号有效性
|
|
412
|
+
**检查点**:
|
|
413
|
+
- `entryRowClick` 事件中是否直接使用行号访问数据而未校验有效性?
|
|
414
|
+
- 行号是否可能为 -1(未选中任何行时)?
|
|
415
|
+
|
|
416
|
+
**风险**: 行号为 -1 时直接 getValue 导致 IndexOutOfBoundsException
|
|
417
|
+
|
|
418
|
+
**修正方案**:
|
|
419
|
+
```java
|
|
420
|
+
// ❌ 错误写法 - 未校验行号
|
|
421
|
+
@Override
|
|
422
|
+
public void entryRowClick(RowClickEvent e) {
|
|
423
|
+
super.entryRowClick(e);
|
|
424
|
+
int row = e.getRow();
|
|
425
|
+
Object value = getModel().getValue("material", row); // row 可能为 -1
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// ✅ 正确写法
|
|
429
|
+
@Override
|
|
430
|
+
public void entryRowClick(RowClickEvent e) {
|
|
431
|
+
super.entryRowClick(e);
|
|
432
|
+
int row = e.getRow();
|
|
433
|
+
if (row < 0) {
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
Object value = getModel().getValue("material", row);
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
### 15. flexEdit 动态编辑控制遗漏
|
|
443
|
+
**检查点**:
|
|
444
|
+
- 使用 `flexEdit` 控制分录字段可编辑性时,是否在 `afterBindData` 和 `afterCreateNewData` 中都设置了?
|
|
445
|
+
- 新增行时是否遗漏了编辑控制?
|
|
446
|
+
|
|
447
|
+
**风险**: 新增行的字段编辑状态与预期不一致
|
|
448
|
+
|
|
449
|
+
**修正方案**:
|
|
450
|
+
```java
|
|
451
|
+
// ❌ 错误写法 - 只在 afterBindData 中设置
|
|
452
|
+
@Override
|
|
453
|
+
public void afterBindData(EventObject e) {
|
|
454
|
+
super.afterBindData(e);
|
|
455
|
+
setEntryFieldEditable();
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// ✅ 正确写法 - afterBindData 和 afterCreateNewData 都设置
|
|
459
|
+
@Override
|
|
460
|
+
public void afterBindData(EventObject e) {
|
|
461
|
+
super.afterBindData(e);
|
|
462
|
+
setEntryFieldEditable();
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
@Override
|
|
466
|
+
public void afterCreateNewData(EventObject e) {
|
|
467
|
+
super.afterCreateNewData(e);
|
|
468
|
+
setEntryFieldEditable();
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
private void setEntryFieldEditable() {
|
|
472
|
+
int rowCount = getModel().getEntryRowCount("entryentity");
|
|
473
|
+
for (int i = 0; i < rowCount; i++) {
|
|
474
|
+
String status = (String) getModel().getValue("linestatus", i);
|
|
475
|
+
getView().setEnable("A".equals(status), i, "qty", "price");
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
### 16. 多页签子页面插件通信错误
|
|
483
|
+
**检查点**:
|
|
484
|
+
- 多页签表单中,子页面插件是否通过 `getView().getParentView()` 获取父页面?
|
|
485
|
+
- 是否在父页面未加载时就尝试访问父页面控件?
|
|
486
|
+
|
|
487
|
+
**风险**: 父页面未加载完成时获取 parentView 为 null,导致 NPE
|
|
488
|
+
|
|
489
|
+
**修正方案**:
|
|
490
|
+
```java
|
|
491
|
+
// ❌ 错误写法 - 未判空 parentView
|
|
492
|
+
@Override
|
|
493
|
+
public void afterBindData(EventObject e) {
|
|
494
|
+
super.afterBindData(e);
|
|
495
|
+
IFormView parentView = getView().getParentView();
|
|
496
|
+
Object parentValue = parentView.getModel().getValue("headField"); // 可能 NPE
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// ✅ 正确写法
|
|
500
|
+
@Override
|
|
501
|
+
public void afterBindData(EventObject e) {
|
|
502
|
+
super.afterBindData(e);
|
|
503
|
+
IFormView parentView = getView().getParentView();
|
|
504
|
+
if (parentView != null && parentView.getModel() != null) {
|
|
505
|
+
Object parentValue = parentView.getModel().getValue("headField");
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
```
|