create-dwy 0.14.7 → 0.16.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 (95) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/bin/index.js +8 -2
  3. package/package.json +1 -1
  4. package/src/skills-install.js +154 -0
  5. package/src/sync-all.js +7 -0
  6. package/templates/ai-tools/CLAUDE.md +28 -1
  7. package/templates/ai-tools/hooks/Git/pre-git-commit-sensitive-check.sh +10 -2
  8. package/templates/ai-tools/rules/Android/dwy-android-pitfalls.md +52 -0
  9. package/templates/ai-tools/rules/HarmonyOS/dwy-arkts-strict.md +221 -0
  10. package/templates/ai-tools/rules/HarmonyOS/dwy-arkts-ui-build.md +193 -0
  11. package/templates/ai-tools/rules/Python/dwy-python-backend.md +16 -63
  12. package/templates/ai-tools/rules/Python/dwy-python-base-lib.md +89 -0
  13. package/templates/ai-tools/rules/Python/dwy-python-pitfalls.md +49 -0
  14. package/templates/ai-tools/rules/Vue/dwy-vue-base-lib.md +127 -0
  15. package/templates/ai-tools/rules/Vue/dwy-vue-core.md +22 -86
  16. package/templates/ai-tools/rules/Vue/dwy-vue-pitfalls.md +66 -0
  17. package/templates/ai-tools/rules/iOS/dwy-ios-pitfalls.md +159 -0
  18. package/templates/ai-tools/rules/iOS/dwy-swift-core.md +35 -0
  19. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-dependency-freshness.md +59 -0
  20. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tdd-development.md +47 -2
  21. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-acceptance/SKILL.md +24 -0
  22. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-architecture/SKILL.md +70 -0
  23. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-commercial/SKILL.md +58 -0
  24. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-competitor/SKILL.md +23 -0
  25. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-explore/SKILL.md +83 -0
  26. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-mvp/SKILL.md +24 -0
  27. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-poc/SKILL.md +24 -0
  28. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-prd/SKILL.md +23 -0
  29. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-product-launcher/SKILL.md +73 -0
  30. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-product-launcher/references/state-and-contract.md +155 -0
  31. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-prototype/SKILL.md +42 -0
  32. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-release/SKILL.md +27 -0
  33. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-design/SKILL.md +30 -0
  34. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-dev/SKILL.md +54 -0
  35. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-launch/SKILL.md +37 -0
  36. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-prd/SKILL.md +31 -0
  37. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-ship/SKILL.md +30 -0
  38. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-tasks/SKILL.md +32 -0
  39. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-tdd-dev/SKILL.md +34 -0
  40. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-validate/SKILL.md +29 -0
  41. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-version/SKILL.md +24 -0
  42. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-github-action-publish/SKILL.md +365 -0
  43. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-github-action-publish/references/electron-release-workflow-template.yml +98 -0
  44. package/templates/ai-tools/skills//{350/277/220/347/273/264/345/217/221/345/270/203/dwy-cibuildwheel → 345/217/221/345/270/203/345/217/221/347/211/210/dwy-github-action-publish}/references/release-workflow-template.yml +3 -3
  45. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/SKILL.md +31 -0
  46. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/android.md +31 -0
  47. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/backend-deploy.md +23 -0
  48. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/changelog.md +37 -0
  49. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/frontend-deploy.md +23 -0
  50. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/generic-release.md +27 -0
  51. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/harmony.md +25 -0
  52. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/ios.md +32 -0
  53. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/monitor-notify.md +36 -0
  54. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/publish-config.md +65 -0
  55. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/version-sync.md +30 -0
  56. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/scripts/release_config.sh +115 -0
  57. package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/SKILL.md +31 -21
  58. package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/references/python-commercial-guide.md +1 -1
  59. package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/references/sensitive-patterns.md +1 -1
  60. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-sdk-spec/scripts/init_config.sh +91 -0
  61. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-whiteboard-prototype/SKILL.md +70 -0
  62. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-whiteboard-prototype/assets/template.html +353 -0
  63. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-sdk-spec/scripts/init_config.sh +0 -97
  64. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-0to1/SKILL.md +0 -113
  65. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-0to1/templates/STATE.md +0 -56
  66. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-dev-qa/SKILL.md +0 -117
  67. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-market-analysis/SKILL.md +0 -92
  68. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prd-coarse/SKILL.md +0 -72
  69. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prd-coarse/templates/prd-coarse.md +0 -61
  70. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prd-detailed/SKILL.md +0 -76
  71. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prd-detailed/templates/prd-detailed.md +0 -119
  72. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prototype/SKILL.md +0 -104
  73. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-publish/SKILL.md +0 -50
  74. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-publish/references/application-release.md +0 -106
  75. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-publish/references/sdk-release.md +0 -93
  76. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-spike/SKILL.md +0 -81
  77. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tdd-dev/SKILL.md +0 -212
  78. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tdd-dev/templates/impl-plan.md +0 -115
  79. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tech-feasibility/SKILL.md +0 -105
  80. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-version-plan/SKILL.md +0 -64
  81. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-version-plan/templates/version-plan.md +0 -72
  82. package/templates/ai-tools/skills//350/277/220/347/273/264/345/217/221/345/270/203/dwy-cibuildwheel/SKILL.md +0 -356
  83. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/assets/files-whitelist-snippet.json" +0 -0
  84. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/assets/js-commercial.npmignore" +0 -0
  85. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/assets/python-commercial-MANIFEST.in" +0 -0
  86. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/assets/python-commercial.gitignore" +0 -0
  87. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/references/js-commercial-guide.md" +0 -0
  88. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/references/publish-blacklist.md" +0 -0
  89. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/scripts/check_comments.py" +0 -0
  90. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/scripts/check_js_publish.sh" +0 -0
  91. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/scripts/check_python_publish.sh" +0 -0
  92. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/scripts/detect_sdk.sh" +0 -0
  93. /package/templates/ai-tools/skills//345/{274/200/345/217/221/346/265/201/347/250/213 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-semver/SKILL.md" +0 -0
  94. /package/templates/ai-tools/skills//345/{274/200/345/217/221/346/265/201/347/250/213 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-semver/references/semver-spec.md" +0 -0
  95. /package/templates/ai-tools/skills//345/{274/200/345/217/221/346/265/201/347/250/213 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-semver/scripts/bump.py" +0 -0
@@ -0,0 +1,193 @@
1
+ ---
2
+ description: HarmonyOS ArkUI 组件层 / V2 状态管理 / 图标资源 / 工程构建 / 运行时容错避坑(与 dwy-arkts-strict.md 语言层配套)
3
+ paths:
4
+ - "**/*.ets"
5
+ - "**/build-profile.json5"
6
+ - "**/main_pages.json"
7
+ ---
8
+
9
+ # ArkUI / 工程 / 运行时 避坑
10
+
11
+ `dwy-arkts-strict.md` 管语言语法层;本文件管 **ArkUI 组件、V2 状态管理、资源(图标)、工程构建、运行时容错**。
12
+ 均为真机/DevEco 构建实测踩坑(编译期或运行期暴露,命令行 tsc 查不出)。
13
+
14
+ ## 1. sys.symbol 图标名 ≠ SF Symbols 名,必须查鸿蒙清单逐个映射
15
+
16
+ iOS 用 SF Symbols(`tv.and.mediabox`),鸿蒙 `$r('sys.symbol.xxx')` 是**另一套命名体系**,
17
+ 大量 SF 名在鸿蒙不存在,写错报 `Unknown resource name 'xxx'`。
18
+
19
+ - **权威清单**:`<DevEco-SDK>/openharmony/toolchains/id_defined.json`(约 4000+ 个,`type=symbol`),
20
+ python 提取后 grep 验证目标名是否存在。
21
+ - **`$r('sys.symbol.x')` 的 x 必须是字面量**,不能用变量动态拼 → 只能逐处改,不能写映射函数。
22
+ - **常见映射**(SF → 鸿蒙):
23
+
24
+ | SF Symbols | 鸿蒙 sys.symbol |
25
+ |---|---|
26
+ | tv / tv.and.mediabox | `TV_tv` |
27
+ | iphone / ipad | `phone` / `pad` |
28
+ | command | `keyboard` |
29
+ | cpu / memorychip | `memory_module` |
30
+ | terminal | `code` |
31
+ | pencil | `doc_plaintext_and_pencil` |
32
+ | globe | `globe_and_keyboard` |
33
+ | tag | `label` |
34
+ | square.and.arrow.up | `share` |
35
+ | checkmark.seal.fill | `checkmark_circle_fill` |
36
+ | stop.fill | `stop_circle_fill` |
37
+ | shippingbox | `card_package` |
38
+ | square.stack.3d.up | `AI_square_stack` |
39
+ | gearshape.fill / house / chevron.left | 同名(`gearshape_fill` / `house` / `chevron_left`,少数直通) |
40
+
41
+ 写前先 `grep -ix '<候选名>' id_defined.txt` 确认存在,别想当然。
42
+
43
+ ## 2. 自定义组件后不能直接链通用属性(margin/layoutWeight/width…)
44
+
45
+ 自定义 `@Component`/`@ComponentV2`(尤其带尾随 `@BuilderParam` 闭包的)**后面直接链通用属性
46
+ 会编译失败**:`Declaration or statement expected` + `Cannot find name 'margin'`。
47
+
48
+ ```typescript
49
+ // 错:HoldRepeatButton 是自定义组件,后链 .margin 解析失败
50
+ HoldRepeatButton({ action: f }) { this.icon() }
51
+ .margin({ bottom: 184 })
52
+
53
+ // 对:外层包系统组件(Column/Row/Stack)再链
54
+ Column() {
55
+ HoldRepeatButton({ action: f }) { this.icon() }
56
+ }.margin({ bottom: 184 })
57
+ ```
58
+
59
+ 需要偏移/尺寸时,要么外层包系统容器,要么给自定义组件加 `@Param` 参数在其内部应用。
60
+
61
+ ## 3. 支持本地初始化的组件属性必须有默认值(mandatory-default-value-for-local-initialization)
62
+
63
+ DevEco **预览器/linter(PreviewBuild)比 assembleHap 更严**,会查这条;assembleHap 不查。
64
+
65
+ - **`@BuilderParam`** 必须给默认值(默认值是一个全局 `@Builder` 函数):
66
+
67
+ ```typescript
68
+ @Builder function emptyContent(): void {}
69
+ @ComponentV2
70
+ struct Foo {
71
+ @BuilderParam content: () => void = emptyContent; // 不能写 `: () => void;`
72
+ }
73
+ ```
74
+
75
+ - **`@CustomDialog` 的 `controller`** 必须可选(否则同报无默认值):
76
+
77
+ ```typescript
78
+ @CustomDialog
79
+ struct MyDialog {
80
+ controller?: CustomDialogController; // 不能写 `controller: CustomDialogController;`
81
+ }
82
+ ```
83
+ 改可选后调用处要用可选链:`this.controller?.close()`(否则 `Object is possibly undefined`)。
84
+
85
+ - **例外**:`@Require @Param x: T;` 不受此规则约束(`@Require` 表必传,无需默认值)。
86
+
87
+ ## 4. @ComponentV2 外部传入的回调属性必须用 @Param
88
+
89
+ 父组件给子组件传属性(含回调)时,子组件该属性必须 `@Param` 装饰,否则报
90
+ `The 'regular' property 'xxx' cannot be initialized here (forbidden to specify)`:
91
+
92
+ ```typescript
93
+ // 错:onDone 是普通属性,父层 Foo({ onDone: ... }) 传不进
94
+ struct Foo { onDone: () => void = () => {}; }
95
+ // 对
96
+ struct Foo { @Param onDone: () => void = () => {}; }
97
+ ```
98
+
99
+ ## 5. async 状态供 UI 同步读:用 @Trace 快照,别在 build 里 await
100
+
101
+ `build()` 是同步的,UI 不能 `await` 一个 async 方法拿状态(`Property 'kind' does not exist on
102
+ type 'Promise<T>'`)。把异步数据在装配/事件时算好,存进 `@Trace` 快照,UI 同步读快照:
103
+
104
+ ```typescript
105
+ @ObservedV2 class Store {
106
+ @Trace snapshot: State = defaultState; // UI 读这个
107
+ private cache = 0;
108
+ async start(ctx): Promise<void> {
109
+ this.cache = await this.loadFromAsset(ctx); // 异步读一次缓存
110
+ this.refresh(); // 用缓存同步算快照
111
+ }
112
+ private refresh(): void { this.snapshot = compute(this.cache, Date.now()); }
113
+ }
114
+ ```
115
+
116
+ ## 6. 跨模块 import 必须从「声明源」取,不能经中转模块隐式重导出
117
+
118
+ ArkTS 不支持 TS 的「A 从 B import 某类型,C 再从 A import 同名」隐式重导出:
119
+ `Module '"../X"' declares 'Y' locally, but it is not exported`。**直接从声明 Y 的那个文件 import**。
120
+
121
+ ```typescript
122
+ // 错:AdbTransport 只是 import 了 AdbLog(没 re-export),别处从 AdbTransport 取 AdbLog
123
+ import { AdbLog } from '../adb/AdbTransport';
124
+ // 对:从声明 AdbLog 的源文件取
125
+ import { AdbLog } from '../adb/AdbConnection';
126
+ ```
127
+
128
+ ## 7. 工程/资源杂项
129
+
130
+ - **`Stack` 居中用 `.alignContent(Alignment.X)`**,不是构造参数 `Stack({ alignment: X })`
131
+ (`'alignment' does not exist in type 'StackOptions'`)。
132
+ - **`SymbolGlyph` 没有 `.textAlign`**:居中靠外层容器的 `justifyContent`/`alignItems`,别链 textAlign。
133
+ - **`build-profile.json5`(entry 模块)顶层字段固定**:apiType/targets/buildOption/buildOptionSet/
134
+ buildModeBinder/entryModules/apiType 等。塞 `testOption` 之类非法字段报
135
+ `Schema validate failed`。hypium 测试靠 `src/ohosTest/` 目录约定,不需在 build-profile 配。
136
+ - **退役/不编译的代码移出 `entry/src/main/ets`**(如 spike):放在 ets 下仍会被编译。
137
+ 移到工程根的 `_archive/` 之类,并从 `main_pages.json` 去掉。
138
+
139
+ ## 8. 运行时:全局状态装配(bootstrap)必须分步容错,不能全有或全无
140
+
141
+ app 入口的「装配全局状态」若把多个步骤串成一个 `await` 链,**任一步抛异常(尤其模拟器/无账号
142
+ 环境下的 IAP、首次无持久化)会让后面全不执行**,导致全局 router/store 为 null,UI 一进就崩
143
+ (`AppContext 未装配` / `Object is possibly undefined`)。
144
+
145
+ ```typescript
146
+ // 错:IAP 在模拟器抛错(如华为 IAP 错误码 27656204)→ router 没装配 → 全崩
147
+ async bootstrap(ctx) {
148
+ await store.load(ctx);
149
+ await iap.start(ctx); // ← 模拟器抛错,下面不执行
150
+ this.router = new Router(...); // ← 永远到不了
151
+ }
152
+
153
+ // 对:每步独立容错,核心对象(router)一定装配成功
154
+ async bootstrap(ctx) {
155
+ await this.safe('存档', () => store.load(ctx));
156
+ await this.safe('内购', () => iap.start(ctx)); // 失败只 log,降级
157
+ this.router = new Router(...); // 一定执行
158
+ }
159
+ private async safe(name, step) {
160
+ try { await step(); } catch (e) { console.error(`[${name}]降级: ${(e as Error).message}`); }
161
+ }
162
+ ```
163
+
164
+ 模块内部同理:**核心数据(如试用锚点)与非关键外部依赖(如 IAP 查询)分开 try**,
165
+ 非关键失败不连累核心,给 UI 一个合理降级默认值。
166
+
167
+ ## 9. DevEco 命令行构建(绕开 IDE,拿带 File:行:列 的错误)
168
+
169
+ ```bash
170
+ NODE=/Applications/DevEco-Studio.app/Contents/tools/node/bin/node
171
+ HVIGOR=/Applications/DevEco-Studio.app/Contents/tools/hvigor/bin/hvigorw.js
172
+ export DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk # 停 daemon 后必设
173
+
174
+ # 配置校验
175
+ $NODE $HVIGOR --sync -p product=default --daemon
176
+ # 编译 + 打 HAP(验 ArkTS 编译;产物 entry/build/.../entry-default-unsigned.hap)
177
+ $NODE $HVIGOR assembleHap -p product=default --mode module -p module=entry@default --daemon \
178
+ 2>&1 | sed 's/\x1b\[[0-9;]*m//g' | grep "Error Message:"
179
+ # 预览器构建(linter 更严,查 @BuilderParam/controller 默认值等;用独立 .preview 缓存)
180
+ $NODE $HVIGOR --mode module -p module=entry@default -p product=default -p pageType=page \
181
+ -p previewMode=true -p buildRoot=.preview PreviewBuild --daemon
182
+ ```
183
+
184
+ - **必须 `--daemon`**:DevEco daemon 自动注入 SDK 路径;`--no-daemon` 报 `Invalid DEVECO_SDK_HOME`。
185
+ - **`Error Message:` 才是阻断错误**;`WARN ... may throw exceptions` 是建议,不阻断。
186
+ - **PreviewBuild 用独立 `.preview` 缓存**:改了源码仍报已修错误 → `rm -rf entry/.preview` 重跑。
187
+ - 两种构建都要过:assembleHap(真机包)+ PreviewBuild(linter 严,预览器)。
188
+
189
+ ## 10. 仍需真机确认的(编译/预览过 ≠ 运行对)
190
+
191
+ 见 `dwy-arkts-strict.md` 第 9 条(cryptoFramework 签名规格 / 公钥 DER 格式 / TCPSocket 局域网)。
192
+ 补充:手撸 HTTP/2 的 HPACK 全字面量是否被对端(如 grpc-netty)接受、华为 IAP 需 AGC 后台
193
+ 配商品 + 真机华为账号、asset/Preferences 在不同设备的可用性,均真机才能定论。
@@ -10,52 +10,6 @@ paths:
10
10
 
11
11
  ---
12
12
 
13
- ## 零、优先使用 `dwyeapi` 基础框架库(强制)
14
-
15
- `dwyeapi` 是团队内部 PyPI 基础设施包,已封装后端项目所需的通用能力。**凡是 dwyeapi 已提供的能力,禁止自行实现,也禁止引入其他库重复造轮子。**
16
-
17
- ### 必须复用 dwyeapi 的能力域
18
-
19
- | 能力域 | 内容 |
20
- |--------|------|
21
- | 配置管理 | 应用 Settings 基类、运行环境识别(dev / prod) |
22
- | 异常体系 | 业务异常基类与全局异常处理器注册 |
23
- | 统一响应 | `{ code, message, data, timestamp }` 包装 |
24
- | 分页 | 分页查询参数模型与分页响应封装 |
25
- | 数据库 | ORM 声明式基类、时间戳 Mixin、异步引擎与会话工厂 |
26
- | 依赖注入 | FastAPI `get_db` 工厂 |
27
- | 安全 | 密码哈希、JWT 创建与解码 |
28
- | 缓存 | 共享异步 Redis 客户端 |
29
- | 时间 | 业务时间统一入口(Asia/Shanghai) |
30
- | 脱敏 | PII 数据脱敏函数 |
31
- | 日志 | 全局日志配置与门面 |
32
- | 健康检查 | 健康检查路由工厂 |
33
- | 异步任务 | 耗时任务队列与上下文 |
34
- | 邮件 | 邮件验证码可插拔通道 |
35
-
36
- ### 查阅方式(关键)
37
-
38
- **在编写任何后端代码前,以及调用任何 dwyeapi 提供的 API 之前,必须先用 `Skill` 工具加载 `dwy-eapi` skill 查阅当前最新接口。** 本文件**只规定约束与边界**,**不固化** dwyeapi 的具体模块路径、类名、函数签名、参数 —— 这些会随版本演进,固化在 rules 里会与实际包不同步。
39
-
40
- ```
41
- Skill 工具调用:skill="dwy-eapi"
42
- ```
43
-
44
- ### 强制规则
45
-
46
- - 涉及上表任一能力域,**先查 skill 拿到当前 API,再写代码**
47
- - **禁止**自造异常基类,必须复用 dwyeapi 异常体系
48
- - **禁止**手写 bcrypt / PyJWT 调用,必须走 dwyeapi 安全模块
49
- - **禁止**自定义统一响应包装函数,必须用 dwyeapi 响应模块
50
- - **禁止**自定义分页模型,必须用 dwyeapi 分页模块
51
- - **禁止**自定义 `DeclarativeBase`,模型必须继承 dwyeapi 提供的基类
52
- - **禁止**在路由函数中直接创建数据库会话,必须用 dwyeapi 依赖工厂
53
- - **禁止**自建 Redis 连接池,必须用 dwyeapi 共享客户端
54
- - **禁止**在业务代码中直接使用 `datetime.now()`,必须用 dwyeapi 时间模块
55
- - **禁止**自行 `logging.basicConfig`,必须用 dwyeapi 日志模块
56
-
57
- ---
58
-
59
13
  ## 一、项目结构与业务聚合(强制)
60
14
 
61
15
  ### 核心原则
@@ -103,7 +57,7 @@ app/
103
57
  - 测试镜像功能聚合结构:`tests/users/test_router.py` / `tests/users/test_service.py`(详见第九节)
104
58
 
105
59
  ### 例外
106
- - 通用基础设施代码(如 dwyeapi 内部)可保持技术层结构
60
+ - 通用基础设施代码(如基础框架库内部)可保持技术层结构
107
61
 
108
62
  ---
109
63
 
@@ -167,11 +121,11 @@ async def create_user(
167
121
 
168
122
  ### 统一响应格式
169
123
 
170
- 所有成功 / 分页 / 错误响应统一走 dwyeapi 响应与异常模块(具体 API 与字段结构查 `dwy-eapi` skill),**禁止**自造响应包装函数,**禁止**在 router 中手动构造 `{"success": true, ...}` 等非标准格式。
124
+ 所有成功 / 分页 / 错误响应统一走项目级响应与异常模块,**禁止**自造响应包装函数,**禁止**在 router 中手动构造 `{"success": true, ...}` 等非标准格式。
171
125
 
172
126
  ### 分页
173
127
 
174
- 分页参数模型与响应包装统一走 dwyeapi(具体 API 查 `dwy-eapi` skill),**禁止**自定义。
128
+ 分页参数模型与响应包装统一走项目级分页模块,**禁止**自定义。
175
129
 
176
130
  ---
177
131
 
@@ -234,7 +188,7 @@ class UserResponse(UserBase):
234
188
 
235
189
  - 数据库会话、当前用户、配置等**必须**通过 `Depends()` 注入
236
190
  - **禁止**在路由函数中直接创建数据库会话或实例化 service
237
- - `get_db` 依赖必须用 dwyeapi 提供的工厂生成(具体 API 查 `dwy-eapi` skill)
191
+ - `get_db` 依赖必须用项目级工厂生成,**禁止**每个路由各自创建
238
192
 
239
193
  ```python
240
194
  # 反例:路由中直接创建会话
@@ -258,8 +212,8 @@ async def get_user(
258
212
 
259
213
  ### 强制规则
260
214
 
261
- - **必须**复用 dwyeapi 异常体系与全局处理器(具体异常类与注册方法查 `dwy-eapi` skill),**禁止**自造异常基类
262
- - 项目级扩展异常必须继承 dwyeapi 异常基类
215
+ - **必须**复用项目级异常体系与全局处理器,**禁止**自造异常基类
216
+ - 项目级扩展异常必须继承统一异常基类
263
217
  - **service 层**抛业务异常,**禁止**抛 `HTTPException`(service 不感知 HTTP)
264
218
  - **router 层**不写 `try / except`,由全局 handler 统一处理
265
219
  - **禁止**裸 `except:` 或 `except Exception: pass`
@@ -273,7 +227,7 @@ async def get_user(
273
227
  ### 强制规则
274
228
 
275
229
  - 必须使用 **SQLAlchemy 2.0** 声明式映射 + async
276
- - 模型继承 dwyeapi 提供的声明式基类与时间戳 Mixin(具体类名查 `dwy-eapi` skill),**禁止**自定义 `DeclarativeBase`
230
+ - 模型继承项目级统一声明式基类与时间戳 Mixin,**禁止**每个模型各自定义 `DeclarativeBase`
277
231
  - 数据库迁移使用 **Alembic**,**禁止**手动执行 DDL
278
232
  - **禁止**在路由层直接写 SQL 查询
279
233
  - **禁止**使用 SQLAlchemy 1.x 风格的 `session.query(...)`
@@ -283,7 +237,7 @@ from sqlalchemy.orm import Mapped, mapped_column
283
237
  from sqlalchemy import String
284
238
  import uuid as uuid_lib
285
239
 
286
- class User(BaseFromDwyeapi, TimestampMixinFromDwyeapi): # 实际基类名以 skill 为准
240
+ class User(Base, TimestampMixin): # 项目级统一基类与时间戳 Mixin
287
241
  __tablename__ = "users"
288
242
 
289
243
  id: Mapped[int] = mapped_column(primary_key=True)
@@ -328,10 +282,10 @@ user = result.scalar_one_or_none()
328
282
 
329
283
  | 规则 | 说明 |
330
284
  |------|------|
331
- | 存储算法 | **只允许 bcrypt**,必须走 dwyeapi 安全模块,**禁止**手写 bcrypt 调用或使用 MD5 / SHA / 明文 |
285
+ | 存储算法 | **只允许 bcrypt**,必须走项目级统一安全模块,**禁止**散落手写 bcrypt 调用或使用 MD5 / SHA / 明文 |
332
286
  | 接口返回 | **永远不返回**密码字段,Response Schema 中不包含 |
333
287
  | 密码强度 | **长度 ≥ 8 字符**,且**必须**包含 **大写字母、小写字母、数字、特殊符号** 中的至少 **3 类** |
334
- | 密码长度上限 | Schema 必须 `max_length=72`(bcrypt 输入硬上限,超过会被静默截断),除非 dwyeapi 已做 SHA-256 预哈希 |
288
+ | 密码长度上限 | Schema 必须 `max_length=72`(bcrypt 输入硬上限,超过会被静默截断),除非安全模块已做 SHA-256 预哈希 |
335
289
  | 登录错误 | 返回"用户名或密码错误",**不区分**是用户名不存在还是密码错误 |
336
290
  | 强度校验位置 | Pydantic Schema 层用 `field_validator` 校验复杂度,**禁止**只校长度 |
337
291
 
@@ -361,12 +315,12 @@ class UserCreate(BaseModel):
361
315
  return v
362
316
  ```
363
317
 
364
- > 该 validator 建议下沉到 dwyeapi 提供统一的 `PasswordStr` 类型,避免每个项目重复实现。
318
+ > 该 validator 建议下沉为项目级统一的 `PasswordStr` 类型,避免每个模块重复实现。
365
319
 
366
320
  ### 7.3 接口认证与授权
367
321
 
368
322
  - 所有 API **必须** JWT 认证(白名单除外:`/health` / `/auth/login` / `/auth/register`)
369
- - JWT 创建与解码**必须**走 dwyeapi 安全模块,**禁止**直接调用 PyJWT
323
+ - JWT 创建与解码**必须**走项目级统一安全模块,**禁止**散落直接调用 PyJWT
370
324
  - Token 黑名单存 Redis(登出后失效,TTL = 剩余有效期)
371
325
  - Secret Key 必须从环境变量读取,**禁止**硬编码
372
326
  - Secret Key 长度与生成方式(按字节算,不按字符算):
@@ -389,7 +343,7 @@ class UserCreate(BaseModel):
389
343
 
390
344
  - **禁止**直接返回 ORM 对象(可能暴露 password、内部 ID 等)
391
345
  - 列表接口**必须**分页,**禁止**返回全量数据
392
- - PII 字段(手机号 / 邮箱 / 身份证 / 银行卡 / 姓名 / 地址 / IP / 车牌)必须使用 dwyeapi 脱敏函数处理
346
+ - PII 字段(手机号 / 邮箱 / 身份证 / 银行卡 / 姓名 / 地址 / IP / 车牌)必须使用项目级统一脱敏函数处理
393
347
 
394
348
  ### 7.5 错误处理安全
395
349
 
@@ -449,7 +403,7 @@ file_path = Path("/uploads") / safe_name
449
403
 
450
404
  ### 7.8 审计日志
451
405
 
452
- 通过 dwyeapi 日志模块获取审计 logger,记录以下操作:
406
+ 通过项目级统一日志模块获取审计 logger,记录以下操作:
453
407
 
454
408
  | 操作 | 记录内容 |
455
409
  |------|---------|
@@ -510,8 +464,7 @@ AI 编写或审查后端代码时,**必须**检查以下违规模式,按严
510
464
 
511
465
  | 检查项 | 违规模式 | 严重程度 |
512
466
  |--------|---------|---------|
513
- | 重复造轮子 | 自造异常基类 / 自封装统一响应 / 手写 bcrypt 或 JWT 调用 / 自建 Redis 连接池 等 dwyeapi 已提供能力 | 高 |
514
- | 未查 skill | 调用 dwyeapi 能力域却未先查 `dwy-eapi` skill 拿当前 API | 高 |
467
+ | 重复造轮子 | 自造异常基类 / 自封装统一响应 / 散落手写 bcrypt 或 JWT 调用 / 自建 Redis 连接池 等本应走项目级统一模块的能力 | 高 |
515
468
  | 技术层散落 | 顶级出现 `routers/` / `services/` / `models/` / `schemas/` 等技术层目录把不同功能文件混放,未按功能聚合 | 高 |
516
469
  | 测试与源码混放 | 测试文件放在源码目录中(如 `app/users/test_router.py`),未独立到测试目录 | 高 |
517
470
  | 密码明文 | `password` 字段出现在 Response Schema | **致命 → STOP** |
@@ -528,5 +481,5 @@ AI 编写或审查后端代码时,**必须**检查以下违规模式,按严
528
481
  | service 抛 HTTPException | service 层直接 `raise HTTPException` | 高 |
529
482
  | 路由中开会话 | 路由函数中 `async with session_factory()` | 高 |
530
483
  | 旧式查询 | `session.query(...)` 而非 `select(...)` | 高 |
531
- | `datetime.now()` 直用 | 业务代码直接 `datetime.now()` 而非走 dwyeapi 时间模块 | 高 |
484
+ | `datetime.now()` 直用 | 业务代码直接 `datetime.now()` 而非走项目级统一时间模块 | 高 |
532
485
  | 物理删除业务数据 | 对业务数据执行物理删除 | 中 |
@@ -0,0 +1,89 @@
1
+ ---
2
+ description: 团队内部 dwyeapi 基础框架库强制复用规范(配置 / 异常 / 响应 / 分页 / ORM / 安全 / 缓存 / 时间 / 脱敏 / 日志:禁重复造轮子)
3
+ paths:
4
+ - "**/*.py"
5
+ ---
6
+
7
+ # Python 后端 dwyeapi 基础库强制复用规范
8
+
9
+ `dwy-python-backend` rule 的团队内补充。通用 FastAPI / SQLAlchemy / 安全编码规范见 `dwy-python-backend`;本文件只管「凡 dwyeapi 已提供的能力,禁止自行实现,也禁止引入其他库重复造轮子」。
10
+
11
+ `dwyeapi` 是团队内部 PyPI 基础设施包,已封装后端项目所需的通用能力。
12
+
13
+ ---
14
+
15
+ ## 一、必须复用 dwyeapi 的能力域
16
+
17
+ | 能力域 | 内容 |
18
+ |--------|------|
19
+ | 配置管理 | 应用 Settings 基类、运行环境识别(dev / prod) |
20
+ | 异常体系 | 业务异常基类与全局异常处理器注册 |
21
+ | 统一响应 | `{ code, message, data, timestamp }` 包装 |
22
+ | 分页 | 分页查询参数模型与分页响应封装 |
23
+ | 数据库 | ORM 声明式基类、时间戳 Mixin、异步引擎与会话工厂 |
24
+ | 依赖注入 | FastAPI `get_db` 工厂 |
25
+ | 安全 | 密码哈希、JWT 创建与解码 |
26
+ | 缓存 | 共享异步 Redis 客户端 |
27
+ | 时间 | 业务时间统一入口(Asia/Shanghai) |
28
+ | 脱敏 | PII 数据脱敏函数 |
29
+ | 日志 | 全局日志配置与门面 |
30
+ | 健康检查 | 健康检查路由工厂 |
31
+ | 异步任务 | 耗时任务队列与上下文 |
32
+ | 邮件 | 邮件验证码可插拔通道 |
33
+
34
+ ### 查阅方式(关键)
35
+
36
+ **在编写任何后端代码前,以及调用任何 dwyeapi 提供的 API 之前,必须先用 `Skill` 工具加载 `dwy-eapi` skill 查阅当前最新接口。** 本文件**只规定约束与边界**,**不固化** dwyeapi 的具体模块路径、类名、函数签名、参数 —— 这些会随版本演进,固化在 rules 里会与实际包不同步。
37
+
38
+ ```
39
+ Skill 工具调用:skill="dwy-eapi"
40
+ ```
41
+
42
+ ---
43
+
44
+ ## 二、强制规则
45
+
46
+ - 涉及上表任一能力域,**先查 skill 拿到当前 API,再写代码**
47
+ - **禁止**自造异常基类,必须复用 dwyeapi 异常体系
48
+ - **禁止**手写 bcrypt / PyJWT 调用,必须走 dwyeapi 安全模块
49
+ - **禁止**自定义统一响应包装函数,必须用 dwyeapi 响应模块
50
+ - **禁止**自定义分页模型,必须用 dwyeapi 分页模块
51
+ - **禁止**自定义 `DeclarativeBase`,模型必须继承 dwyeapi 提供的基类
52
+ - **禁止**在路由函数中直接创建数据库会话,必须用 dwyeapi 依赖工厂
53
+ - **禁止**自建 Redis 连接池,必须用 dwyeapi 共享客户端
54
+ - **禁止**在业务代码中直接使用 `datetime.now()`,必须用 dwyeapi 时间模块
55
+ - **禁止**自行 `logging.basicConfig`,必须用 dwyeapi 日志模块
56
+
57
+ ---
58
+
59
+ ## 三、各能力域 dwyeapi 落点
60
+
61
+ 通用规范(路由 / Schema / ORM / 安全编码本身的要求)见 `dwy-python-backend` 对应章节;本节只说明这些规范在团队项目里**必须落到哪个 dwyeapi 模块**。
62
+
63
+ | 能力 | 团队项目落点 | 对应通用规范 |
64
+ |------|-------------|-------------|
65
+ | 统一响应 / 异常 | dwyeapi 响应模块 + 异常体系(禁自造) | backend 二、五 |
66
+ | 分页 | dwyeapi 分页模块(禁自定义) | backend 二 |
67
+ | ORM 基类 / 时间戳 | 继承 dwyeapi 声明式基类与 Mixin | backend 六 |
68
+ | `get_db` 依赖 | dwyeapi 依赖工厂 | backend 四 |
69
+ | 密码哈希 | dwyeapi 安全模块(bcrypt,禁手写) | backend 7.2 |
70
+ | JWT 创建 / 解码 | dwyeapi 安全模块(禁直接 PyJWT) | backend 7.3 |
71
+ | PII 脱敏 | dwyeapi 脱敏函数 | backend 7.4 |
72
+ | 审计日志 | dwyeapi 日志模块获取审计 logger | backend 7.8 |
73
+ | 业务时间 | dwyeapi 时间模块(禁裸 `datetime.now()`) | backend 六 / 七 |
74
+ | Redis 缓存 | dwyeapi 共享客户端(禁自建连接池) | backend 八 |
75
+
76
+ > 密码复杂度校验建议下沉到 dwyeapi 提供统一的 `PasswordStr` 类型,避免每个项目重复实现。
77
+
78
+ ---
79
+
80
+ ## 四、违规检测清单(dwyeapi 相关)
81
+
82
+ 通用后端违规清单见 `dwy-python-backend` 第十节;涉及 dwyeapi 必须额外检查:
83
+
84
+ | 检查项 | 违规模式 | 严重程度 |
85
+ |--------|---------|---------|
86
+ | 重复造轮子 | 自造异常基类 / 自封装统一响应 / 手写 bcrypt 或 JWT 调用 / 自建 Redis 连接池 等 dwyeapi 已提供能力 | 高 |
87
+ | 未查 skill | 调用 dwyeapi 能力域却未先查 `dwy-eapi` skill 拿当前 API | 高 |
88
+ | 密码弱存储 | 使用 MD5 / SHA 而非 dwyeapi 安全模块的 bcrypt | **致命 → STOP** |
89
+ | `datetime.now()` 直用 | 业务代码直接 `datetime.now()` 而非走 dwyeapi 时间模块 | 高 |
@@ -0,0 +1,49 @@
1
+ ---
2
+ description: Python 后端开发避坑清单(FastAPI / SQLAlchemy / async / 依赖 / 部署踩坑),按分类持续追加
3
+ paths:
4
+ - "**/*.py"
5
+ - "**/pyproject.toml"
6
+ - "**/uv.lock"
7
+ ---
8
+
9
+ # Python 开发坑清单
10
+
11
+ > 动手前先对照本清单避开已知坑;踩到新坑随手按四栏格式(现象 / 根因 / 正确做法 / 适用)追加到对应分类,没有合适分类就新建一个。
12
+ >
13
+ > 通用开发规范见 `dwy-python-core` / `dwy-python-backend` rule,本文件只记**非显而易见的实战坑**。
14
+
15
+ ## 分类索引
16
+
17
+ - 依赖与环境(uv / venv / 版本)
18
+ - async / 并发(事件循环、阻塞调用、连接池)
19
+ - FastAPI / Pydantic(路由、Schema、校验、序列化)
20
+ - SQLAlchemy / ORM(异步 session、懒加载、事务)
21
+ - 部署与运行时(打包、环境变量、进程模型)
22
+ - 排查方法论
23
+ - 其他分类遇到再加
24
+
25
+ ---
26
+
27
+ ## 依赖与环境
28
+
29
+ <!-- 待填:踩到坑按四栏格式追加 -->
30
+
31
+ ## async / 并发
32
+
33
+ <!-- 待填 -->
34
+
35
+ ## FastAPI / Pydantic
36
+
37
+ <!-- 待填 -->
38
+
39
+ ## SQLAlchemy / ORM
40
+
41
+ <!-- 待填 -->
42
+
43
+ ## 部署与运行时
44
+
45
+ <!-- 待填 -->
46
+
47
+ ## 排查方法论
48
+
49
+ <!-- 待填 -->
@@ -0,0 +1,127 @@
1
+ ---
2
+ description: 团队内部基础库强制复用规范(eui UI 组件 + ekit 工具:禁重复造轮子、HTTP/存储/日期/校验/脱敏走 ekit、UI 走 eui)
3
+ paths:
4
+ - "**/*.vue"
5
+ - "**/*.ts"
6
+ ---
7
+
8
+ # Vue 团队基础库强制复用规范
9
+
10
+ `dwy-vue-core` rule 的团队内补充。通用 Vue 工程规范见 `dwy-vue-core`;本文件只管「凡 eui / ekit 已提供的能力,禁止自行实现,也禁止引入其他库重复造轮子」。
11
+
12
+ `@dwydev/eui` 与 `@dwydev/ekit` 是团队内部 npm 基础库,分别覆盖 UI 组件层与通用工具层。
13
+
14
+ ---
15
+
16
+ ## 一、必须复用的能力域
17
+
18
+ | 能力域 | 归属 |
19
+ |--------|------|
20
+ | 通用 UI 组件(Button / Input / Select / Dialog / Drawer / Form / Table 等) | eui |
21
+ | 主题 / 设计 tokens / 暗色模式 | eui |
22
+ | 表单校验(vee-validate + zod 集成) | eui + ekit |
23
+ | 中后台 / 落地页设计规范 | eui(references) |
24
+ | HTTP 客户端(拦截器 / token / 刷新 / 解包) | ekit |
25
+ | 本地存储 / Cookie | ekit(storage / cookie) |
26
+ | 日期 / 时间格式化 | ekit(date) |
27
+ | 数据校验 schema | ekit(validators) |
28
+ | PII 数据脱敏 | ekit(masking) |
29
+ | 剪贴板 / 文件下载 / qs 序列化 | ekit |
30
+ | VueUse 再导出(debounce / throttle / clickOutside / mediaQuery 等) | ekit(hooks) |
31
+
32
+ ### 查阅方式(关键)
33
+
34
+ **在编写任何 Vue 代码前,以及调用任何 eui / ekit 提供的 API 之前,必须先用 `Skill` 工具加载对应 skill 查阅当前最新接口。** 本文件只规定约束与边界,**不固化**组件 props、函数签名 —— 这些会随版本演进,固化在 rule 里会与实际包不同步。
35
+
36
+ ```
37
+ Skill 工具调用:
38
+ - skill="dwy-eui" 组件库 API 与设计规范
39
+ - skill="dwy-ekit" 工具库 API 与契约
40
+ ```
41
+
42
+ ---
43
+
44
+ ## 二、强制规则
45
+
46
+ - **禁止**业务代码出现 `axios` / `fetch` / `new XMLHttpRequest`,HTTP 走 ekit `createRequest`
47
+ - **禁止**直接 `localStorage.getItem` / `setItem` / `removeItem`,走 ekit storage / `useStorage`
48
+ - **禁止**直接 `document.cookie` 或单独引入 `js-cookie`,走 ekit cookie
49
+ - **禁止**业务代码 `new Date()` / `toLocaleString` / 直接 `import dayjs`,走 ekit date
50
+ - **禁止**手写 `navigator.clipboard` / `document.addEventListener('click', ...)` 监听,走 ekit copy / hooks
51
+ - **禁止**自定义已有 UI 组件(Button / Input / Select / Dialog / Form / Table 等),走 eui
52
+ - **禁止**自定义已有日期 / 时间 / 验证 / 脱敏 / 下载 工具函数,走 ekit
53
+ - 涉及任一能力域,**先查 skill 拿到当前 API,再写代码**
54
+
55
+ ---
56
+
57
+ ## 三、API 请求
58
+
59
+ ### 强制规则
60
+
61
+ - HTTP 客户端**必须**用 ekit `createRequest` 创建,全局唯一实例放 `core/http.ts`(具体参数与插件查 `dwy-ekit` skill)
62
+ - **禁止**业务代码 `axios.create()` / `fetch()` / `new XMLHttpRequest()`
63
+ - 响应解包契约与 dwyeapi 对齐(`{ code, message, data }`),具体类型与守卫查 `dwy-ekit` skill
64
+ - 401 / 422 / 业务错误的统一处理由 ekit request 插件完成(具体 API 查 `dwy-ekit` skill)
65
+ - 业务侧 catch 用 ekit 提供的 `isApiBusinessError` 类型守卫做分支(`NOT_FOUND` / `VALIDATION_ERROR` / `PERMISSION_DENIED` 等)
66
+
67
+ > API 函数的目录归属、独立导出、类型标注等结构约定见 `dwy-vue-core` 第六节。
68
+
69
+ ### 示例
70
+
71
+ ```typescript
72
+ // core/http.ts —— 全局唯一 HTTP 客户端(具体 plugins 查 dwy-ekit skill)
73
+ import { createRequest } from '@dwydev/ekit'
74
+
75
+ export const request = createRequest({
76
+ baseURL: import.meta.env.VITE_API_BASE_URL,
77
+ plugins: [
78
+ /* tokenPlugin / refreshTokenPlugin / unwrapPlugin —— 具体用法查 dwy-ekit skill */
79
+ ],
80
+ })
81
+
82
+ // modules/users/api.ts —— 该业务的 API
83
+ import { request } from '@/core/http'
84
+ import type { UserInfo, UserCreate } from './types'
85
+
86
+ export function getUsers(params: { page: number; page_size: number }) {
87
+ return request.get<{ items: UserInfo[]; total: number }>('/users', { params })
88
+ }
89
+
90
+ export function createUser(data: UserCreate) {
91
+ return request.post<UserInfo>('/users', data)
92
+ }
93
+ ```
94
+
95
+ ---
96
+
97
+ ## 四、通用 hooks 走 ekit
98
+
99
+ 通用 hooks(debounce / throttle / clickOutside / mediaQuery 等)**禁止**自己造,走 ekit hooks(具体 API 查 `dwy-ekit` skill)。
100
+
101
+ ---
102
+
103
+ ## 五、样式覆盖 eui
104
+
105
+ 覆盖 eui 内部样式用 scoped CSS + `:deep(...)`(其余样式规范见 `dwy-vue-core` 第八节,优先 Tailwind)。
106
+
107
+ ---
108
+
109
+ ## 六、错误拦截走 ekit
110
+
111
+ 401 / 422 / 业务错误的拦截走 ekit request 插件(查 `dwy-ekit` skill),**禁止**每个 API 都包 try-catch。业务侧统一在页面级或 store 级处理,用 `isApiBusinessError` 守卫分支。
112
+
113
+ ---
114
+
115
+ ## 七、违规检测清单(基础库相关)
116
+
117
+ AI 编写或审查 Vue 代码时,涉及 eui / ekit 必须检查以下违规模式(通用框架违规清单见 `dwy-vue-core` 第十四节):
118
+
119
+ | 检查项 | 违规模式 | 严重程度 |
120
+ |--------|---------|---------|
121
+ | 未查 skill | 使用 eui / ekit API 前未先查 `dwy-eui` / `dwy-ekit` skill | 高 |
122
+ | ekit 重复造轮子 | 自造 HTTP / storage / cookie / date / 校验 / 脱敏 等 ekit 已提供能力 | 高 |
123
+ | eui 重复造轮子 | 自造已有 UI 组件(Button / Input / Dialog 等) | 高 |
124
+ | 组件直调 axios | 组件内 `axios.get` / `fetch` / `new XMLHttpRequest` | **致命 → STOP** |
125
+ | 直接 localStorage | `localStorage.getItem` / `setItem` 出现在业务代码 | 高 |
126
+ | 直接 new Date | `new Date()` / `toLocaleString` / 直接 `import dayjs` | 高 |
127
+ | 旧 axios 例子 | 业务里出现 `axios.create()` / `interceptors.request.use(...)` | **致命 → STOP** |