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.
Files changed (219) hide show
  1. package/README.md +358 -0
  2. package/dist/cli/kcode.d.ts +15 -0
  3. package/dist/cli/kcode.js +153 -0
  4. package/dist/cli/main.d.ts +2 -0
  5. package/dist/cli/main.js +7 -0
  6. package/docs/KCODE_DISTRIBUTION.md +91 -0
  7. package/extensions/kingdee-harness.ts +180 -0
  8. package/extensions/kingdee-header.ts +122 -0
  9. package/extensions/kingdee-tools.ts +379 -0
  10. package/knowledge/.backup/v1.0.0/version.json +10 -0
  11. package/knowledge/cangqiong/product-notes.md +15 -0
  12. package/knowledge/common/business-flows.md +115 -0
  13. package/knowledge/common/config-guides.md +110 -0
  14. package/knowledge/common/error-patterns.md +170 -0
  15. package/knowledge/common/implementation.md +144 -0
  16. package/knowledge/cosmic/hard-constraints.md +38 -0
  17. package/knowledge/cosmic/ksql-datafix.md +34 -0
  18. package/knowledge/cosmic/platform-baseline.md +32 -0
  19. package/knowledge/cosmic/plugin-decision-matrix.md +40 -0
  20. package/knowledge/cosmic/review-checklist.md +40 -0
  21. package/knowledge/cosmic/unittest.md +35 -0
  22. package/knowledge/enterprise/api-reference.md +186 -0
  23. package/knowledge/enterprise/code-patterns.md +217 -0
  24. package/knowledge/enterprise/plugin-lifecycle.md +188 -0
  25. package/knowledge/enterprise/tables.json +159 -0
  26. package/knowledge/flagship/api-reference.md +237 -0
  27. package/knowledge/flagship/code-patterns.md +246 -0
  28. package/knowledge/flagship/cosmic-platform-note.md +15 -0
  29. package/knowledge/flagship/plugin-lifecycle.md +248 -0
  30. package/knowledge/flagship/tables.json +159 -0
  31. package/knowledge/version.json +10 -0
  32. package/knowledge/xinghan/product-notes.md +15 -0
  33. package/package.json +71 -0
  34. package/prompts/kd-discuss.md +11 -0
  35. package/prompts/kd-execute.md +12 -0
  36. package/prompts/kd-plan.md +12 -0
  37. package/prompts/kd-ship.md +12 -0
  38. package/prompts/kd-spec.md +12 -0
  39. package/prompts/kd-verify.md +12 -0
  40. package/skills/kd-check/SKILL.md +26 -0
  41. package/skills/kd-cosmic-dev/SKILL.md +82 -0
  42. package/skills/kd-cosmic-review/SKILL.md +90 -0
  43. package/skills/kd-cosmic-unittest/SKILL.md +92 -0
  44. package/skills/kd-debug/SKILL.md +30 -0
  45. package/skills/kd-discuss/SKILL.md +24 -0
  46. package/skills/kd-execute/SKILL.md +22 -0
  47. package/skills/kd-gen/SKILL.md +34 -0
  48. package/skills/kd-ksql/SKILL.md +86 -0
  49. package/skills/kd-plan/SKILL.md +24 -0
  50. package/skills/kd-ship/SKILL.md +22 -0
  51. package/skills/kd-spec/SKILL.md +24 -0
  52. package/skills/kd-verify/SKILL.md +22 -0
  53. package/themes/kcode-dark.json +81 -0
  54. package/vendor/kingdee-skills/cosmic-unittest/SKILL.md +788 -0
  55. package/vendor/kingdee-skills/cosmic-unittest/author-cache.json +5 -0
  56. package/vendor/kingdee-skills/cosmic-unittest/cosmic-unittest-skill-overview.html +746 -0
  57. package/vendor/kingdee-skills/cosmic-unittest/examples/business-test.md +205 -0
  58. package/vendor/kingdee-skills/cosmic-unittest/examples/common-test.md +257 -0
  59. package/vendor/kingdee-skills/cosmic-unittest/examples/formplugin-test.md +560 -0
  60. package/vendor/kingdee-skills/cosmic-unittest/examples/op-plugin-test.md +231 -0
  61. package/vendor/kingdee-skills/cosmic-unittest/examples/validator-test.md +232 -0
  62. package/vendor/kingdee-skills/cosmic-unittest/patterns/business-helper.md +184 -0
  63. package/vendor/kingdee-skills/cosmic-unittest/patterns/common-module.md +355 -0
  64. package/vendor/kingdee-skills/cosmic-unittest/patterns/convert-plugin.md +130 -0
  65. package/vendor/kingdee-skills/cosmic-unittest/patterns/formplugin.md +235 -0
  66. package/vendor/kingdee-skills/cosmic-unittest/patterns/op-plugin.md +226 -0
  67. package/vendor/kingdee-skills/cosmic-unittest/patterns/validator.md +206 -0
  68. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/SKILL.md +674 -0
  69. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/advanced-scenario-checklist.md +307 -0
  70. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/algox-performance-checklist.md +129 -0
  71. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/coding-standard-checklist.md +491 -0
  72. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/cosmic-api-checklist.md +285 -0
  73. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/data-access-checklist.md +261 -0
  74. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/data-transaction-checklist.md +390 -0
  75. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/domain-logic-checklist.md +295 -0
  76. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/form-plugin-checklist.md +508 -0
  77. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/infra-checklist.md +254 -0
  78. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/ksql-checklist.md +305 -0
  79. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/lifecycle-checklist.md +298 -0
  80. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/operation-plugin-checklist.md +442 -0
  81. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/test-mock-checklist.md +120 -0
  82. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/ui-performance-checklist.md +320 -0
  83. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/pattern-matcher.py +336 -0
  84. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/review-score-calculator.py +121 -0
  85. package/vendor/kingdee-skills/ok-cosmic/CHANGELOG.md +295 -0
  86. package/vendor/kingdee-skills/ok-cosmic/README.md +460 -0
  87. package/vendor/kingdee-skills/ok-cosmic/SKILL.md +287 -0
  88. package/vendor/kingdee-skills/ok-cosmic/agents/openai.yaml +17 -0
  89. package/vendor/kingdee-skills/ok-cosmic/assets/BatchImportPluginTemplate.java +93 -0
  90. package/vendor/kingdee-skills/ok-cosmic/assets/BillPlugInTemplate.java +156 -0
  91. package/vendor/kingdee-skills/ok-cosmic/assets/ConvertPlugInTemplate.java +255 -0
  92. package/vendor/kingdee-skills/ok-cosmic/assets/FormPluginTemplate.java +597 -0
  93. package/vendor/kingdee-skills/ok-cosmic/assets/IWorkflowPluginTemplate.java +91 -0
  94. package/vendor/kingdee-skills/ok-cosmic/assets/ListPluginTemplate.java +194 -0
  95. package/vendor/kingdee-skills/ok-cosmic/assets/OpPluginTemplate.java +201 -0
  96. package/vendor/kingdee-skills/ok-cosmic/assets/OpenApiControllerTemplate.java +103 -0
  97. package/vendor/kingdee-skills/ok-cosmic/assets/PrintPluginTemplate.java +95 -0
  98. package/vendor/kingdee-skills/ok-cosmic/assets/ReportFormPluginTemplate.java +257 -0
  99. package/vendor/kingdee-skills/ok-cosmic/assets/ReportListDataPluginTemplate.java +70 -0
  100. package/vendor/kingdee-skills/ok-cosmic/assets/StandardTreeListPluginTemplate.java +130 -0
  101. package/vendor/kingdee-skills/ok-cosmic/assets/TaskTemplate.java +80 -0
  102. package/vendor/kingdee-skills/ok-cosmic/assets/TreeListPluginTemplate.java +152 -0
  103. package/vendor/kingdee-skills/ok-cosmic/assets/WriteBackPlugInTemplate.java +286 -0
  104. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/attachment/AttachmentUploadBindSample.java +93 -0
  105. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/botp/BotpTracePushSample.java +168 -0
  106. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/botp/SampleConvertPlugin.java +223 -0
  107. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/cache/SampleCacheUsage.java +218 -0
  108. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/concurrent/SampleThreadPoolBatch.java +156 -0
  109. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/data/DynamicObjectCrudSample.java +205 -0
  110. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/data/DynamicObjectOpsSample.java +100 -0
  111. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/BeforeOperationConfirmSample.java +217 -0
  112. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ConfirmDialogSample.java +131 -0
  113. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/EntryRowCalculateSample.java +116 -0
  114. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/F7FilterSample.java +134 -0
  115. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/GetAndSetValueSample.java +176 -0
  116. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/HyperlinkJumpSample.java +124 -0
  117. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/OpenBillModalSample.java +253 -0
  118. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ReturnParentDataSample.java +295 -0
  119. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/TreeControlSample.java +140 -0
  120. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ViewControlOpsSample.java +132 -0
  121. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/list/ListPluginBasicSample.java +170 -0
  122. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/list/ListPreOpenFilterSample.java +68 -0
  123. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/message/MessageNotifySample.java +95 -0
  124. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/mq/SampleMQConsumer.java +198 -0
  125. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/mq/sample_mq.xml +15 -0
  126. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/operation/OpAddValidatorsSample.java +137 -0
  127. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/operation/OperationOptionBridgeSample.java +228 -0
  128. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/package-info.java +19 -0
  129. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/BaseDataQuerySample.java +194 -0
  130. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/BatchQuerySample.java +368 -0
  131. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/DataSetQueryStatSample.java +131 -0
  132. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportFormPlugin.java +179 -0
  133. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportListDataPlugin.java +616 -0
  134. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/snippets-guide.md +64 -0
  135. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/task/ScheduleTaskSample.java +160 -0
  136. package/vendor/kingdee-skills/ok-cosmic/assets/snippets/workflow/SampleWorkflowPlugin.java +302 -0
  137. package/vendor/kingdee-skills/ok-cosmic/manifest.json +78 -0
  138. package/vendor/kingdee-skills/ok-cosmic/ok-cosmic-intro.html +903 -0
  139. package/vendor/kingdee-skills/ok-cosmic/references/adv/attachment-api.md +114 -0
  140. package/vendor/kingdee-skills/ok-cosmic/references/adv/botp-convert.md +98 -0
  141. package/vendor/kingdee-skills/ok-cosmic/references/adv/dynamic-object.md +113 -0
  142. package/vendor/kingdee-skills/ok-cosmic/references/adv/entity-metadata.md +123 -0
  143. package/vendor/kingdee-skills/ok-cosmic/references/adv/event-lifecycle.md +184 -0
  144. package/vendor/kingdee-skills/ok-cosmic/references/adv/flex-prop.md +114 -0
  145. package/vendor/kingdee-skills/ok-cosmic/references/adv/form-utils.md +133 -0
  146. package/vendor/kingdee-skills/ok-cosmic/references/adv/operate-chain.md +159 -0
  147. package/vendor/kingdee-skills/ok-cosmic/references/adv/plugin-base.md +218 -0
  148. package/vendor/kingdee-skills/ok-cosmic/references/adv/query-dataset.md +149 -0
  149. package/vendor/kingdee-skills/ok-cosmic/references/adv/request-context.md +88 -0
  150. package/vendor/kingdee-skills/ok-cosmic/references/adv/view-handler.md +157 -0
  151. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-bill.md +76 -0
  152. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-botp.md +70 -0
  153. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-form.md +165 -0
  154. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-import.md +69 -0
  155. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-list.md +227 -0
  156. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-openapi.md +112 -0
  157. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-operation.md +135 -0
  158. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-print.md +65 -0
  159. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-report-data.md +64 -0
  160. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-report-form.md +90 -0
  161. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-task.md +62 -0
  162. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-tree-list.md +71 -0
  163. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-workflow.md +82 -0
  164. package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-writeback.md +71 -0
  165. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-algo.md +67 -0
  166. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-cache.md +63 -0
  167. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-dynamic-model-svc.md +82 -0
  168. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-dynamic-object.md +70 -0
  169. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-entity-model.md +61 -0
  170. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-exception.md +64 -0
  171. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-file.md +63 -0
  172. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-id.md +47 -0
  173. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-lock.md +61 -0
  174. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-log.md +63 -0
  175. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-network-control.md +70 -0
  176. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-orm-access.md +78 -0
  177. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-request-context.md +62 -0
  178. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-threadpool.md +63 -0
  179. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-tx.md +64 -0
  180. package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-utils.md +67 -0
  181. package/vendor/kingdee-skills/ok-cosmic/requirements.txt +2 -0
  182. package/vendor/kingdee-skills/ok-cosmic/rules/a-layer-rules.json +24 -0
  183. package/vendor/kingdee-skills/ok-cosmic/rules/anti-patterns.md +48 -0
  184. package/vendor/kingdee-skills/ok-cosmic/rules/cheat-sheet.md +256 -0
  185. package/vendor/kingdee-skills/ok-cosmic/rules/coding-preferences.md +140 -0
  186. package/vendor/kingdee-skills/ok-cosmic/rules/constraints.md +61 -0
  187. package/vendor/kingdee-skills/ok-cosmic/rules/decision-matrix.md +222 -0
  188. package/vendor/kingdee-skills/ok-cosmic/rules/intent-routing.md +94 -0
  189. package/vendor/kingdee-skills/ok-cosmic/rules/platform-baseline.md +69 -0
  190. package/vendor/kingdee-skills/ok-cosmic/rules/post-check.md +109 -0
  191. package/vendor/kingdee-skills/ok-cosmic/scripts/config_loader.py +204 -0
  192. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-api-knowledge.py +910 -0
  193. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-basedata-query.py +359 -0
  194. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-config-check.py +181 -0
  195. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-extpoints-query.py +389 -0
  196. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-form-metadata.py +856 -0
  197. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-check.py +262 -0
  198. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-lint.py +293 -0
  199. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/__init__.py +2 -0
  200. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/base.py +393 -0
  201. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/resource_check.py +176 -0
  202. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/scene_check.py +375 -0
  203. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/style_check.py +434 -0
  204. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/verify_check.py +36 -0
  205. package/vendor/kingdee-skills/ok-cosmic/scripts/route_client.py +186 -0
  206. package/vendor/kingdee-skills/ok-cosmic/scripts/script_utils.py +40 -0
  207. package/vendor/kingdee-skills/ok-cosmic/scripts/sqlite_cache.py +142 -0
  208. package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-commons.jar +0 -0
  209. package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-features.jar +0 -0
  210. package/vendor/kingdee-skills/ok-cosmic/setup/ok-cosmic-docs.db +0 -0
  211. package/vendor/kingdee-skills/ok-cosmic/setup/ok-cosmic.json +13 -0
  212. package/vendor/kingdee-skills/ok-cosmic/setup/setup-mac.sh +18 -0
  213. package/vendor/kingdee-skills/ok-cosmic/setup/setup-windows.bat +53 -0
  214. package/vendor/kingdee-skills/ok-cosmic/setup/setup.jar +0 -0
  215. package/vendor/kingdee-skills/ok-ksql/SKILL.md +81 -0
  216. package/vendor/kingdee-skills/ok-ksql/agents/openai.yaml +7 -0
  217. package/vendor/kingdee-skills/ok-ksql/manifest.json +14 -0
  218. package/vendor/kingdee-skills/ok-ksql/references/ksql-datafix.md +452 -0
  219. package/vendor/kingdee-skills/ok-ksql/scripts/ksql_lint.py +363 -0
@@ -0,0 +1,320 @@
1
+ # UI 交互与性能陷阱检查表
2
+
3
+ ## 🟠 P1 级问题
4
+
5
+ ### 1. 循环内刷新视图
6
+ **检查点**:
7
+ - 循环内是否调用了 `updateView()`?
8
+ - 是否频繁触发界面刷新?
9
+
10
+ **风险**: 界面卡顿,CPU 飙升
11
+
12
+ **修正方案**:
13
+ ```java
14
+ // ❌ 错误写法
15
+ for (int i = 0; i < 100; i++) {
16
+ this.getModel().setValue("field" + i, value);
17
+ this.getView().updateView(); // 每次循环都刷新!
18
+ }
19
+
20
+ // ✅ 正确写法 - 使用 beginInit/endInit 包裹
21
+ this.getView().beginInit();
22
+ try {
23
+ for (int i = 0; i < 100; i++) {
24
+ this.getModel().setValue("field" + i, value);
25
+ }
26
+ } finally {
27
+ this.getView().endInit();
28
+ }
29
+ ```
30
+
31
+ ---
32
+
33
+ ### 2. 错误的行号获取
34
+ **检查点**:
35
+ - 是否直接使用 `e.getInsertRow()` 获取行号?
36
+
37
+ **风险**: 可能获取到错误的行号
38
+
39
+ **修正方案**:
40
+ ```java
41
+ // ❌ 错误写法
42
+ int row = e.getInsertRow();
43
+
44
+ // ✅ 正确写法
45
+ int row = e.getRowDataEntities()[0].getRowIndex();
46
+ ```
47
+
48
+ ---
49
+
50
+ ### 3. 循环内获取 FieldIndex
51
+ **检查点**:
52
+ - 循环内是否重复调用 `getFieldIndex()`?
53
+
54
+ **修正方案**:
55
+ ```java
56
+ // ❌ 错误写法
57
+ for (DynamicObject row : rows) {
58
+ int idx = this.getModel().getFieldIndex("amount");
59
+ this.getModel().setValue(idx, row.getBigDecimal("amount"));
60
+ }
61
+
62
+ // ✅ 正确写法
63
+ int idx = this.getModel().getFieldIndex("amount"); // 循环外缓存
64
+ for (DynamicObject row : rows) {
65
+ this.getModel().setValue(idx, row.getBigDecimal("amount"));
66
+ }
67
+ ```
68
+
69
+ ---
70
+
71
+ ### 4. 无限累积集合
72
+ **检查点**:
73
+ - 静态 List/Map 是否只增不减?
74
+
75
+ **风险**: OOM 内存溢出
76
+
77
+ **修正方案**:
78
+ ```java
79
+ // ✅ 使用有界缓存
80
+ private static final int MAX_SIZE = 10000;
81
+ private static LinkedHashMap<Long, Object> cache = new LinkedHashMap<>(16, 0.75f, true) {
82
+ @Override
83
+ protected boolean removeEldestEntry(Map.Entry<Long, Object> eldest) {
84
+ return size() > MAX_SIZE;
85
+ }
86
+ };
87
+ ```
88
+
89
+ ---
90
+
91
+ ## 🟡 P2 级问题
92
+
93
+ ### 5. 表格数据量过大
94
+ **检查点**:
95
+ - 表格是否加载了超过 1000 行?
96
+
97
+ **修正方案**:
98
+ ```java
99
+ // 使用分页查询
100
+ int pageSize = 500;
101
+ DataSet ds = QueryServiceHelper.queryDataSet(...)
102
+ .limit(pageSize);
103
+ ```
104
+
105
+ ---
106
+
107
+ ### 6. 过度使用 invokeLater
108
+ **检查点**:
109
+ - 是否在非 UI 线程频繁调用 `invokeLater`?
110
+
111
+ **修正方案**:
112
+ ```java
113
+ // 合并多个 invokeLater 调用
114
+ this.getView().invokeLater(() -> {
115
+ // 批量处理 UI 更新
116
+ updateAllFields();
117
+ });
118
+ ```
119
+
120
+ ---
121
+
122
+ ### 7. 大数据包循环 setValue
123
+ **检查点**:
124
+ - 分录行数 > 100 条时是否在循环中使用 `model.setValue`?
125
+ - 应改用 `property.setValueFast` 提升性能
126
+
127
+ **风险**: 大批量 setValue 触发大量 propertyChanged 事件,界面严重卡顿
128
+
129
+ **修正方案**:
130
+ ```java
131
+ // ❌ 错误写法 - 大数据包循环 setValue
132
+ for (int i = 0; i < 500; i++) {
133
+ getModel().setValue("field1", value1, i);
134
+ getModel().setValue("field2", value2, i);
135
+ }
136
+
137
+ // ✅ 正确写法 - 使用 setValueFast
138
+ DynamicObjectCollection entries = getModel().getEntryEntity("entryEntity");
139
+ for (DynamicObject entry : entries) {
140
+ for (DynamicProperty property : treeEntryProperties) {
141
+ property.setValueFast(newObj, objProps.get(property.getName()).getValueFast(srcObj));
142
+ }
143
+ }
144
+ getView().updateView("entryEntity"); // 循环外统一刷新
145
+ ```
146
+
147
+ ---
148
+
149
+ ### 8. setValue 后未 updateView
150
+ **检查点**:
151
+ - `getModel().setValue()` 之后是否调用了 `getView().updateView()`?
152
+ - 分录操作后是否刷新了界面?
153
+
154
+ **风险**: 数据已修改但界面不刷新,用户看到旧数据
155
+
156
+ **修正方案**:
157
+ ```java
158
+ // ❌ 错误写法 - 忘记刷新
159
+ getModel().setValue("fieldKey", value);
160
+
161
+ // ✅ 正确写法
162
+ getModel().setValue("fieldKey", value);
163
+ getView().updateView("fieldKey");
164
+ ```
165
+
166
+ ---
167
+
168
+ ### 9. beginInit/endInit 不成对
169
+ **检查点**:
170
+ - `beginInit()` 和 `endInit()` 是否成对出现?
171
+ - 是否在 finally 块中调用 `endInit()` 确保异常时也能结束?
172
+
173
+ **风险**: 遗漏 endInit 导致后续所有 setValue 不触发 propertyChanged,表单行为异常
174
+
175
+ **修正方案**:
176
+ ```java
177
+ // ❌ 错误写法 - 不成对
178
+ getModel().beginInit();
179
+ getModel().setValue("field1", val1);
180
+ getModel().setValue("field2", val2);
181
+ // 忘记 endInit()
182
+
183
+ // ✅ 正确写法 - try-finally 确保成对
184
+ getModel().beginInit();
185
+ try {
186
+ getModel().setValue("field1", val1);
187
+ getModel().setValue("field2", val2);
188
+ getModel().setValue("field3", val3);
189
+ } finally {
190
+ getModel().endInit();
191
+ }
192
+ getView().updateView();
193
+ ```
194
+
195
+ ---
196
+
197
+ ### 10. setDataChanged 调用时机错误
198
+ **检查点**:
199
+ - `setDataChanged(false)` 是否放在所有 `setValue` 之后?
200
+ - 是否在 `afterBindData` 末尾调用 `setDataChanged(false)`?
201
+
202
+ **风险**: 提前调用后续 setValue 又会将 dataChanged 设为 true,导致关闭页面时误提示"数据已修改"
203
+
204
+ **修正方案**:
205
+ ```java
206
+ // ❌ 错误写法 - setDataChanged 没放最后
207
+ getModel().setDataChanged(false);
208
+ getModel().setValue("fieldA", value); // 这行让 dataChanged 重新变 true
209
+
210
+ // ✅ 正确写法 - 所有 setValue 完成后再调
211
+ getModel().setValue("fieldA", value);
212
+ getModel().setDataChanged(false);
213
+ ```
214
+
215
+ ---
216
+
217
+ ### 11. showConfirm 无回调监听器
218
+ **检查点**:
219
+ - `showConfirm` 是否提供了 `ConfirmCallBackListener`?
220
+ - 回调方法 `confirmCallBack` 是否正确处理了用户选择?
221
+
222
+ **风险**: 确认框无法接收用户选择结果
223
+
224
+ **修正方案**:
225
+ ```java
226
+ // ❌ 错误写法 - 无回调
227
+ getView().showConfirm(message, MessageBoxOptions.OKCancel, null);
228
+
229
+ // ✅ 正确写法
230
+ getView().showConfirm(message, MessageBoxOptions.OKCancel,
231
+ new ConfirmCallBackListener("callbackId", this));
232
+ ```
233
+
234
+ ---
235
+
236
+ ### 12. close 和 returnDataToParent 顺序错误
237
+ **检查点**:
238
+ - 是否先调用 `close()` 再调用 `returnDataToParent()`?(应先返回数据再关闭)
239
+
240
+ **风险**: 先 close 后 returnDataToParent 永远不会执行
241
+
242
+ **修正方案**:
243
+ ```java
244
+ // ❌ 错误写法
245
+ getView().close();
246
+ getView().returnDataToParent(data); // 永远不会执行
247
+
248
+ // ✅ 正确写法
249
+ getView().returnDataToParent(data);
250
+ getView().close();
251
+ ```
252
+
253
+ ---
254
+
255
+ ### 13. DynamicObject/DynamicObjectCollection 未判空
256
+ **检查点**:
257
+ - 读取 F7 基础资料字段前是否判空?
258
+ - 访问分录集合前是否判空?(`entries == null || entries.isEmpty()`)
259
+ - 嵌套分录访问是否逐层判空?
260
+ - BigDecimal 计算前是否判空?
261
+
262
+ **风险**: NullPointerException
263
+
264
+ **修正方案**:
265
+ ```java
266
+ // ❌ 错误写法 - 未判空
267
+ DynamicObject org = (DynamicObject) getModel().getValue("org");
268
+ Long orgId = org.getLong("id"); // org 可能为 null
269
+
270
+ // ✅ 正确写法
271
+ DynamicObject org = (DynamicObject) getModel().getValue("org");
272
+ if (org != null) {
273
+ Long orgId = org.getLong("id");
274
+ }
275
+
276
+ // ❌ 错误写法 - 嵌套访问未逐层判空
277
+ DynamicObject subRow = entries.get(0).getDynamicObjectCollection("subentry").get(0);
278
+
279
+ // ✅ 正确写法 - 逐层判空
280
+ if (entries != null && !entries.isEmpty()) {
281
+ DynamicObject parentRow = entries.get(0);
282
+ DynamicObjectCollection subEntries = parentRow.getDynamicObjectCollection("subentry");
283
+ if (subEntries != null && !subEntries.isEmpty()) {
284
+ DynamicObject subRow = subEntries.get(0);
285
+ }
286
+ }
287
+ ```
288
+
289
+ ---
290
+
291
+ ### 14. 列表按钮操作未校验选中行
292
+ **检查点**:
293
+ - 列表 `itemClick` 中是否先获取选中行再执行业务逻辑?
294
+ - 未选中行时是否提示用户?
295
+
296
+ **风险**: 未选中行时直接执行导致空指针或逻辑错误
297
+
298
+ **修正方案**:
299
+ ```java
300
+ // ❌ 错误写法 - 未校验选中行
301
+ @Override
302
+ public void itemClick(ItemClickEvent evt) {
303
+ if ("btnExport".equals(evt.getItemKey())) {
304
+ processSelected(getSelectedRows()); // 可能为空
305
+ }
306
+ }
307
+
308
+ // ✅ 正确写法
309
+ @Override
310
+ public void itemClick(ItemClickEvent evt) {
311
+ if ("btnExport".equals(evt.getItemKey())) {
312
+ List<Object> selectedIds = this.getSelectedRows();
313
+ if (selectedIds.isEmpty()) {
314
+ getView().showTipNotification("请先选择数据");
315
+ return;
316
+ }
317
+ processSelected(selectedIds);
318
+ }
319
+ }
320
+ ```
@@ -0,0 +1,336 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ 金蝶代码问题模式匹配器
4
+ 用于快速识别代码中的严重问题
5
+
6
+ 使用方法:
7
+ python pattern-matcher.py <file_path>
8
+
9
+ 输出:
10
+ - P0 级问题(阻断/严重)
11
+ - P1 级问题(高危/性能)
12
+ - P2 级问题(规范/建议)
13
+ """
14
+
15
+ import re
16
+ import sys
17
+ from typing import List, Tuple, Dict, Optional
18
+
19
+ # ==========================================
20
+ # 上下文验证函数(减少误判)
21
+ # ==========================================
22
+
23
+ def _is_in_try_with_resources(code: str, match_start: int) -> bool:
24
+ """检查匹配位置是否在 try-with-resources 块内"""
25
+ # 向前查找最近的 try( 语句
26
+ before = code[:match_start]
27
+ # 查找最近的 try 块
28
+ try_pos = before.rfind('try (')
29
+ try_pos2 = before.rfind('try(')
30
+ try_pos = max(try_pos, try_pos2)
31
+ if try_pos == -1:
32
+ return False
33
+ # 检查 try 和 match 之间是否有闭合的 }
34
+ between = before[try_pos:]
35
+ open_braces = between.count('{') - between.count('}')
36
+ return open_braces > 0
37
+
38
+ def _is_in_comment(code: str, match_start: int) -> bool:
39
+ """检查匹配位置是否在注释中"""
40
+ # 检查是否在单行注释中
41
+ line_start = code.rfind('\n', 0, match_start) + 1
42
+ line = code[line_start:match_start]
43
+ if '//' in line:
44
+ return True
45
+ # 检查是否在多行注释中
46
+ last_open = code.rfind('/*', 0, match_start)
47
+ if last_open != -1:
48
+ last_close = code.rfind('*/', 0, match_start)
49
+ if last_close < last_open:
50
+ return True
51
+ return False
52
+
53
+ def _is_org_user_id_field(match_text: str) -> bool:
54
+ """检查是否是组织/用户/部门相关字段(真正的硬编码ID问题)"""
55
+ id_field_patterns = [
56
+ r'"[^"]*org[^"]*"', # 组织相关
57
+ r'"[^"]*user[^"]*"', # 用户相关
58
+ r'"[^"]*dept[^"]*"', # 部门相关
59
+ r'"[^"]*creator[^"]*"', # 创建人
60
+ r'"[^"]*modifier[^"]*"', # 修改人
61
+ r'"[^"]*approver[^"]*"', # 审核人
62
+ ]
63
+ for pattern in id_field_patterns:
64
+ if re.search(pattern, match_text, re.IGNORECASE):
65
+ return True
66
+ return False
67
+
68
+ def _is_null_checked_before(code: str, var_name: str, match_start: int) -> bool:
69
+ """检查变量在使用前是否已做过空检查"""
70
+ before = code[:match_start]
71
+ # 查找最近100个字符内是否有空检查
72
+ check_range = before[-200:] if len(before) > 200 else before
73
+ null_check_patterns = [
74
+ rf'{var_name}\s*!=\s*null',
75
+ rf'{var_name}\s*==\s*null',
76
+ rf'Optional\.ofNullable\s*\(\s*{var_name}',
77
+ rf'if\s*\(\s*{var_name}\s*!=\s*null',
78
+ ]
79
+ for pattern in null_check_patterns:
80
+ if re.search(pattern, check_range):
81
+ return True
82
+ return False
83
+
84
+
85
+ # ==========================================
86
+ # P0 级问题模式定义(阻断/严重)
87
+ # ==========================================
88
+
89
+ PATTERNS_P0 = [
90
+ # 生命周期问题
91
+ (r'public\s+void\s+initialize\s*\([^)]*\)\s*\{[^}]*addItemClickListener',
92
+ 'Initialize 注册监听', 'lifecycle-checklist.md', '内存泄漏,监听器无法正确释放'),
93
+ (r'public\s+void\s+initialize\s*\([^)]*\)\s*\{[^}]*getView\(\)',
94
+ 'Initialize 操作 UI', 'lifecycle-checklist.md', '生命周期违规'),
95
+
96
+ # 事务问题
97
+ (r'beforeExecuteOperationTransaction[^}]*SaveServiceHelper\.save',
98
+ '操作插件独立保存破坏事务', 'data-transaction-checklist.md', '事务分离,数据不一致,无法回滚'),
99
+ (r'afterExecuteOperationTransaction[^}]*SaveServiceHelper\.save',
100
+ '操作插件独立保存破坏事务', 'data-transaction-checklist.md', '事务分离,数据不一致'),
101
+
102
+ # 资源泄漏 - DataSet(需上下文验证:排除已在 try-with-resources 中的情况)
103
+ (r'DataSet\s+\w+\s*=\s*QueryServiceHelper\.',
104
+ 'DataSet 查询未使用 try-with-resources', 'data-transaction-checklist.md', '连接池耗尽,系统崩溃',
105
+ 'check_try_with_resources'),
106
+ (r'DataSet\s+\w+\s*=\s*Algo\.',
107
+ 'DataSet (Algo) 未使用 try-with-resources', 'data-transaction-checklist.md', '计算资源泄漏',
108
+ 'check_try_with_resources'),
109
+
110
+ # 资源泄漏 - AlgoContext(需上下文验证)
111
+ (r'AlgoContext\s+\w+\s*=\s*Algo\.newContext\(\)',
112
+ 'AlgoContext 可能未关闭', 'data-transaction-checklist.md', '计算资源泄漏',
113
+ 'check_try_with_resources'),
114
+
115
+ # 硬编码组织/用户 ID(缩小匹配范围,仅匹配 org/user/dept 相关字段)
116
+ (r'\.set\s*\(\s*"[^"]*(org|creator|modifier|approver|dept|user)[^"]*"\s*,\s*\d{4,}L?\s*\)',
117
+ '硬编码组织/用户 ID', 'data-transaction-checklist.md', '跨环境部署失败'),
118
+
119
+ # 空指针风险 - P0级(链式调用未判空)
120
+ (r'getDynamicObject\s*\(\s*"[^"]+"\s*\)\.getPkValue\s*\(',
121
+ 'getDynamicObject() 结果未判空调用 getPkValue', 'coding-standard-checklist.md', 'NullPointerException'),
122
+ (r'getDynamicObject\s*\(\s*"[^"]+"\s*\)\.getString\s*\(',
123
+ 'getDynamicObject() 结果未判空调用 getString', 'coding-standard-checklist.md', 'NullPointerException'),
124
+ (r'getDynamicObject\s*\(\s*"[^"]+"\s*\)\.getBigDecimal\s*\(',
125
+ 'getDynamicObject() 结果未判空调用 getBigDecimal', 'coding-standard-checklist.md', 'NullPointerException'),
126
+ (r'getDynamicObject\s*\(\s*"[^"]+"\s*\)\.getLong\s*\(',
127
+ 'getDynamicObject() 结果未判空调用 getLong', 'coding-standard-checklist.md', 'NullPointerException'),
128
+
129
+ # 分布式锁未在 finally 释放
130
+ (r'\.lock\s*\(\s*\)[^}]*(?!finally)',
131
+ '分布式锁可能未在 finally 中释放', 'infra-checklist.md', '锁永久不释放,线程阻塞'),
132
+ ]
133
+
134
+ # ==========================================
135
+ # P1 级问题模式定义(高危/性能)
136
+ # ==========================================
137
+
138
+ PATTERNS_P1 = [
139
+ # 性能问题 - UI
140
+ (r'for\s*\([^)]+\)\s*\{[^}]*updateView\s*\(',
141
+ '循环内调用 updateView', 'ui-performance-checklist.md', '界面卡顿'),
142
+ (r'while\s*\([^)]+\)\s*\{[^}]*updateView\s*\(',
143
+ '循环内调用 updateView', 'ui-performance-checklist.md', '界面卡顿'),
144
+ (r'for\s*\([^)]+\)\s*\{[^}]*getFieldIndex\s*\(',
145
+ '循环内获取 FieldIndex', 'ui-performance-checklist.md', '性能损耗'),
146
+
147
+ # 性能问题 - 数据库
148
+ (r'for\s*\([^)]+\)\s*\{[^}]*BusinessDataServiceHelper\.loadSingle',
149
+ '循环内调用 loadSingle', 'data-transaction-checklist.md', 'N+1 查询问题'),
150
+ (r'for\s*\([^)]+\)\s*\{[^}]*BusinessDataServiceHelper\.load\s*\(',
151
+ '循环内调用 load', 'data-transaction-checklist.md', 'N+1 查询问题'),
152
+ (r'for\s*\([^)]+\)\s*\{[^}]*SaveServiceHelper\.save',
153
+ '循环内调用 save', 'data-transaction-checklist.md', '性能问题+事务风险'),
154
+ (r'for\s*\([^)]+\)\s*\{[^}]*QueryServiceHelper\.query',
155
+ '循环内调用 QueryServiceHelper', 'data-transaction-checklist.md', 'N+1 查询问题'),
156
+ (r'for\s*\([^)]+\)\s*\{[^}]*DispatchServiceHelper\.invoke',
157
+ '循环内调用微服务', 'data-transaction-checklist.md', 'N+1 远程调用'),
158
+
159
+ # 空指针风险 - P1级
160
+ (r'getDataEntities\s*\(\s*\)\s*\[\s*\d+\s*\]',
161
+ 'getDataEntities() 数组访问未判空', 'coding-standard-checklist.md', 'ArrayIndexOutOfBoundsException'),
162
+ (r'this\.dataEntities\s*\[',
163
+ 'dataEntities 数组访问未判空', 'coding-standard-checklist.md', '空指针风险'),
164
+
165
+ # JDK 原生线程
166
+ (r'new\s+Thread\s*\(',
167
+ '使用 JDK 原生 Thread', 'infra-checklist.md', '绕过平台线程管理'),
168
+ (r'Executors\.\s*new\w+Pool',
169
+ '使用 JDK 原生线程池', 'infra-checklist.md', '绕过平台线程管理'),
170
+
171
+ # System.out
172
+ (r'System\s*\.\s*out\s*\.\s*print',
173
+ '使用 System.out 而非平台日志', 'coding-standard-checklist.md', '日志不规范'),
174
+
175
+ # 集合问题
176
+ (r'\.size\s*\(\s*\)\s*>\s*0',
177
+ '建议使用 !isEmpty() 替代 size()>0', 'coding-standard-checklist.md', '代码可读性'),
178
+
179
+ # MQ publisher 未关闭
180
+ (r'createSimplePublisher\s*\([^)]*\)',
181
+ 'MQ Publisher 可能未关闭', 'infra-checklist.md', '资源泄漏',
182
+ 'check_try_with_resources'),
183
+ ]
184
+
185
+ # ==========================================
186
+ # P2 级问题模式定义(规范/建议)
187
+ # ==========================================
188
+
189
+ PATTERNS_P2 = [
190
+ # 编码规范
191
+ (r'private\s+final\s+\w+\s+ZERO\s*=\s*BigDecimal\.ZERO',
192
+ 'ZERO 字段应声明为 static final', 'coding-standard-checklist.md', '内存浪费'),
193
+ (r'public\s+\w+\s*\(\s*\)\s*\{\s*super\s*\(\s*\)\s*;\s*\}',
194
+ '冗余的空构造函数', 'coding-standard-checklist.md', '代码冗余'),
195
+ (r'logger\.error\s*\(\s*"[^"]+"\s*\)',
196
+ '异常日志缺少堆栈信息', 'coding-standard-checklist.md', '排查困难'),
197
+ (r'new\s+Object\[\s*0\s*\]',
198
+ 'new Object[0] 可简化', 'coding-standard-checklist.md', '代码冗余'),
199
+
200
+ # e.printStackTrace
201
+ (r'\.printStackTrace\s*\(\s*\)',
202
+ '禁止直接调用 printStackTrace', 'coding-standard-checklist.md', '日志不规范'),
203
+
204
+ # 空 catch 块
205
+ (r'catch\s*\(\s*\w+\s+\w+\s*\)\s*\{\s*\}',
206
+ '空 catch 块隐藏异常', 'coding-standard-checklist.md', '异常被吞'),
207
+
208
+ # BigDecimal 问题(降级为 P2 - 仅在 DataSet.Row 场景下才是真正风险)
209
+ (r'row\.getBigDecimal\s*\(\s*"[^"]+"\s*\)\.compareTo',
210
+ 'DataSet Row.getBigDecimal() 结果可能为 null', 'coding-standard-checklist.md', '空指针风险'),
211
+ ]
212
+
213
+
214
+ def match_patterns(code: str, patterns: List[Tuple], level: str) -> List[dict]:
215
+ """匹配代码中的问题模式,支持上下文验证减少误判"""
216
+ issues = []
217
+ for pattern_data in patterns:
218
+ # 支持带上下文验证的5元组格式和普通4/3元组格式
219
+ context_check = None
220
+ if len(pattern_data) == 5:
221
+ pattern, desc, ref, risk, context_check = pattern_data
222
+ elif len(pattern_data) == 4:
223
+ pattern, desc, ref, risk = pattern_data
224
+ else:
225
+ pattern, desc, ref = pattern_data
226
+ risk = '未指定'
227
+
228
+ matches = re.finditer(pattern, code, re.DOTALL | re.IGNORECASE)
229
+ for match in matches:
230
+ # 跳过注释中的匹配
231
+ if _is_in_comment(code, match.start()):
232
+ continue
233
+
234
+ # 上下文验证:检查是否在 try-with-resources 中
235
+ if context_check == 'check_try_with_resources':
236
+ if _is_in_try_with_resources(code, match.start()):
237
+ continue # 已在 try-with-resources 中,不是问题
238
+
239
+ issues.append({
240
+ 'level': level,
241
+ 'description': desc,
242
+ 'reference': ref,
243
+ 'risk': risk,
244
+ 'match': match.group()[:100] + '...' if len(match.group()) > 100 else match.group(),
245
+ 'start': match.start(),
246
+ 'end': match.end()
247
+ })
248
+ return issues
249
+
250
+ def analyze_file(filepath: str) -> List[dict]:
251
+ """分析单个文件"""
252
+ try:
253
+ with open(filepath, 'r', encoding='utf-8') as f:
254
+ code = f.read()
255
+
256
+ p0_issues = match_patterns(code, PATTERNS_P0, 'P0')
257
+ p1_issues = match_patterns(code, PATTERNS_P1, 'P1')
258
+ p2_issues = match_patterns(code, PATTERNS_P2, 'P2')
259
+
260
+ return p0_issues + p1_issues + p2_issues
261
+ except Exception as e:
262
+ print(f"Error reading file: {e}")
263
+ return []
264
+
265
+ def print_report(issues: List[dict]):
266
+ """打印格式化的报告"""
267
+ if not issues:
268
+ print("\n✅ 未发现 P0/P1/P2 级问题模式\n")
269
+ return
270
+
271
+ # 按级别分组
272
+ p0 = [i for i in issues if i['level'] == 'P0']
273
+ p1 = [i for i in issues if i['level'] == 'P1']
274
+ p2 = [i for i in issues if i['level'] == 'P2']
275
+
276
+ print(f"\n{'='*60}")
277
+ print(f"📊 模式匹配扫描报告")
278
+ print(f"{'='*60}")
279
+ print(f" 总计发现 {len(issues)} 个潜在问题\n")
280
+
281
+ if p0:
282
+ print(f"🔴 P0 级问题 ({len(p0)} 个):")
283
+ for i, issue in enumerate(p0, 1):
284
+ print(f" {i}. {issue['description']}")
285
+ print(f" 风险: {issue['risk']}")
286
+ print(f" 参考: references/{issue['reference']}")
287
+ print()
288
+
289
+ if p1:
290
+ print(f"🟠 P1 级问题 ({len(p1)} 个):")
291
+ for i, issue in enumerate(p1, 1):
292
+ print(f" {i}. {issue['description']}")
293
+ print(f" 风险: {issue['risk']}")
294
+ print(f" 参考: references/{issue['reference']}")
295
+ print()
296
+
297
+ if p2:
298
+ print(f"🟡 P2 级问题 ({len(p2)} 个):")
299
+ for i, issue in enumerate(p2, 1):
300
+ print(f" {i}. {issue['description']}")
301
+ print(f" 风险: {issue['risk']}")
302
+ print(f" 参考: references/{issue['reference']}")
303
+ print()
304
+
305
+ # 计算评分
306
+ base_score = 100
307
+ score = base_score - len(p0) * 15 - len(p1) * 8 - len(p2) * 3
308
+ score = max(0, score)
309
+
310
+ print(f"{'='*60}")
311
+ print(f"📐 综合评分: {score} 分", end="")
312
+ if score >= 90:
313
+ print(" (优秀)")
314
+ elif score >= 75:
315
+ print(" (良好)")
316
+ elif score >= 60:
317
+ print(" (中等)")
318
+ else:
319
+ print(" (需改进)")
320
+ print(f"{'='*60}\n")
321
+
322
+ def main():
323
+ if len(sys.argv) < 2:
324
+ print("Usage: python pattern-matcher.py <file_path>")
325
+ print("\n示例:")
326
+ print(" python pattern-matcher.py MyPlugin.java")
327
+ sys.exit(1)
328
+
329
+ filepath = sys.argv[1]
330
+ print(f"\n🔍 正在扫描文件: {filepath}")
331
+
332
+ issues = analyze_file(filepath)
333
+ print_report(issues)
334
+
335
+ if __name__ == '__main__':
336
+ main()