create-dwy 0.16.0 → 0.17.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/CHANGELOG.md +17 -0
- package/bin/index.js +1 -1
- package/package.json +3 -2
- package/src/searchable-select.js +419 -0
- package/src/sync-all.js +313 -65
- package/src/sync-global-skills.js +167 -0
- package/src/sync.js +59 -43
- package/templates/ai-tools/CHANGELOG.md +210 -0
- package/templates/ai-tools/VERSION +1 -0
- package/templates/ai-tools/hook-manifests/hooks.json +7 -0
- package/templates/ai-tools/hooks/Git/pre-git-commit-ai-signature-check.sh +57 -0
- package/templates/ai-tools/rules/Android/dwy-android-core.md +280 -5
- package/templates/ai-tools/rules/Docker/dwy-docker.md +52 -1
- package/templates/ai-tools/rules/HarmonyOS/dwy-arkts-ui-build.md +50 -1
- package/templates/ai-tools/rules/HarmonyOS/dwy-arkts-ui-design.md +139 -0
- package/templates/ai-tools/rules/HarmonyOS/dwy-harmony-pitfalls.md +72 -0
- package/templates/ai-tools/rules/Python/dwy-python-core.md +47 -0
- package/templates/ai-tools/rules/Vue/dwy-vue-core.md +55 -0
- package/templates/ai-tools/rules/iOS/dwy-ios-pitfalls.md +7 -0
- package/templates/ai-tools/rules/iOS/dwy-swift-core.md +46 -0
- package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-git-commit.md +9 -6
- package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-oss-commercial-license.md +128 -0
- package/templates/ai-tools/skills//345/205/203/345/267/245/345/205/267/dwy-shared/SKILL.md +22 -1
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-ios-app-store-release/SKILL.md +65 -0
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-ios-app-store-release/assets/appstore-submission.yaml +43 -0
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-ios-app-store-release/references/api-workflow.md +17 -0
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-ios-app-store-release/references/in-app-purchase-review.md +16 -0
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-ios-app-store-release/references/screenshot-workflow.md +16 -0
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-ios-app-store-release/scripts/appstore_config.sh +140 -0
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/SKILL.md +11 -8
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/android.md +2 -1
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/backend-deploy.md +2 -1
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/changelog.md +24 -4
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/frontend-deploy.md +2 -1
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/generic-release.md +2 -1
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/git-tag.md +82 -0
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/harmony.md +2 -1
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/ios.md +3 -2
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/monitor-notify.md +2 -2
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-semver/SKILL.md +1 -1
- package/templates/ai-tools/skills//345/237/272/347/241/200/345/272/223/dwy-eapi/references/tasks-integration-guide.md +2 -2
- package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/SKILL.md +1 -1
- package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/references/checks-runtime.md +2 -2
- package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_docker.sh +3 -3
- package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_secrets.sh +1 -1
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/README.md +57 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/SKILL.md +147 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/references/api.md +43 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/references/config.example.yaml +33 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/scripts/global_config.py +89 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/scripts/setup_config.py +175 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/scripts/synthesize.py +339 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/SKILL.md +127 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/assets/cover-style-master-v1.png +0 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/references/platform-copy-examples.md +37 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/references/platform-posting-times.md +193 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0005-ideation/SKILL.md +42 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0005-ideation/templates/topic-backlog.template.md +50 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0005-ideation/templates//351/200/211/351/242/230/346/261/240.template.md +16 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0010-product/SKILL.md +106 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0010-product/templates/channel-profile.template.md +52 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0010-product/templates//344/272/247/345/223/201/345/215/241.template.md +132 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0030-facts/SKILL.md +60 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0030-facts/scripts/build_facts_html.py +430 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0030-facts/scripts/generate_html.py +1287 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0030-facts/scripts/generate_report.py +189 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0030-facts/templates//344/272/213/345/256/236/350/265/204/346/226/231/345/272/223.template.md +55 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0040-script/SKILL.md +36 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0040-script/templates/README.md +10 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0040-script/templates//344/272/213/345/256/236.template.md +82 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0040-script/templates//345/215/225/351/233/206/346/226/207/346/241/243.template.md +175 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0040-script/templates//350/204/232/346/234/254.template.md +69 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0040-script/templates//351/252/250/346/236/266-v1.1.md +174 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0050-design/SKILL.md +55 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0060-assets/SKILL.md +29 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package/SKILL.md +42 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package/scripts/validate_shots.py +207 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package/shots.schema.json +186 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package//344/272/272/345/256/241/345/214/205.template.md +1 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package//344/272/272/345/256/241/350/257/264/346/230/216.md +15 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package//346/210/220/347/211/207/345/214/205.template.md +49 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0080-factory/SKILL.md +58 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-comic-kit/SKILL.md +424 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-comic-kit/evals.md +41 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-flow/CONTRACT.md +123 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-flow/SKILL.md +81 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-flow//346/211/247/350/241/214/346/270/205/345/215/225.template.md +60 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/SKILL.md +78 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/agents/openai.yaml +4 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/assets/knowledge-town-paper-film-v1.json +80 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/assets/remotion/AudioTracks.tsx +20 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/assets/remotion/CaptionLayer.tsx +18 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/assets/remotion/CueTimeline.ts +24 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/assets/remotion/KnowledgeTownComposition.tsx +21 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/references/cinematic-direction.md +73 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/references/sticker-asset-production.md +30 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/references/style-guide.md +43 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/scripts/build_cue_timeline.py +75 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/scripts/validate_cue_timeline.py +68 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/scripts/validate_style_preset.py +22 -0
- package/templates/ai-tools/skills//350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-first/SKILL.md +176 -0
- package/templates/ai-tools/skills//350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-first/references/chapter-01-mirrors.md +112 -0
|
@@ -336,7 +336,7 @@ fun computeDiscount(order: Order): BigDecimal {
|
|
|
336
336
|
|
|
337
337
|
### 2.6 字段 / 属性注释(强制)
|
|
338
338
|
|
|
339
|
-
|
|
339
|
+
公开属性、`data class` 构造参数、配置常量必须逐个注释。**数据实体**除注释外还须遵守 §四「数据实体类封装」:Java 注释写在 **private 字段**上,Kotlin 用 `@property`。
|
|
340
340
|
|
|
341
341
|
```kotlin
|
|
342
342
|
/**
|
|
@@ -356,6 +356,26 @@ data class User(
|
|
|
356
356
|
```
|
|
357
357
|
|
|
358
358
|
```java
|
|
359
|
+
/**
|
|
360
|
+
* 用户信息实体。字段私有,经 getter / setter 访问。
|
|
361
|
+
*/
|
|
362
|
+
public class User {
|
|
363
|
+
/** 用户 ID,服务端分配,> 0 */
|
|
364
|
+
private long id;
|
|
365
|
+
/** 昵称,1-32 字符 */
|
|
366
|
+
private String name;
|
|
367
|
+
|
|
368
|
+
public long getId() {
|
|
369
|
+
return id;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
public void setId(long id) {
|
|
373
|
+
this.id = id;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// ... 其余 get/set、toString 见 §四「数据实体类封装」
|
|
377
|
+
}
|
|
378
|
+
|
|
359
379
|
public final class Constants {
|
|
360
380
|
/** 登录态本地缓存的 SP key,迁移版本时不允许复用此 key,会读到旧数据。 */
|
|
361
381
|
public static final String SP_KEY_LOGIN_TOKEN = "login_token_v2";
|
|
@@ -407,7 +427,7 @@ public final class Constants {
|
|
|
407
427
|
| 有参数 / 返回值 / 异常 | 多行,含 `@param` / `@return` / `@throws` | ✓ |
|
|
408
428
|
| Activity / Fragment | 必须注明入口、参数 key、返回结果 | ✓ |
|
|
409
429
|
| 回调接口 | 必须注明触发线程 + 每个参数语义 | ✓ |
|
|
410
|
-
| `data class`
|
|
430
|
+
| `data class` / Java 实体字段 | Kotlin `@property`;Java **private 字段**上 `/** */` + get/set | ✓ |
|
|
411
431
|
| 复杂业务规则 | 行内注释解释 why + 关联 PRD / 需求号 | ✓ |
|
|
412
432
|
| 重写方法 | `@inheritDoc` 或重新写明覆写差异 | ✓ |
|
|
413
433
|
| Gradle 脚本(Groovy) | 解释 why:锁版本/exclude 原因、变体用途、自定义 task/方法语义(详见 §2.10) | ✓ |
|
|
@@ -434,6 +454,70 @@ val data = newService.fetch()
|
|
|
434
454
|
// TODO(zhang, 2026-05-30): 兼容企业微信扫码,关联 issue #1234
|
|
435
455
|
```
|
|
436
456
|
|
|
457
|
+
### 2.9.1 临时代码标识(强制 · Java / Kotlin / XML)
|
|
458
|
+
|
|
459
|
+
产品源码(`src/main` 等)中的业务待办、调试旁路、假数据**必须**用固定标签,便于 AS TODO 窗口 / 全局搜索定位。`src/test`、`androidTest` 正规测试 mock **不强制**。
|
|
460
|
+
|
|
461
|
+
| 标签 | 用途 | 格式 |
|
|
462
|
+
|---|---|---|
|
|
463
|
+
| `TODO` | 业务/技术未完成 | `// TODO(name, YYYY-MM-DD): 说明`(同 §2.9) |
|
|
464
|
+
| `TESTCODE` | 临时调试、跳过校验、试验开关 | `// TESTCODE: 说明 + 移除条件` |
|
|
465
|
+
| `MOCK` | 假数据、假接口、stub 实现 | `// MOCK: 说明 + 将来替换点` |
|
|
466
|
+
|
|
467
|
+
- 注释符:Java/Kotlin 用 `//`;XML 用 `<!-- -->`
|
|
468
|
+
- 写 mock/调试代码的**同一 diff 必须带标**;接真实现后**删标签与包夹**
|
|
469
|
+
- 禁止无标签假返回;禁止自造 `// 假数据`、`// test only` 等替代词
|
|
470
|
+
- 发版/提测前搜 `MOCK`、`TESTCODE`,清单交给负责人确认(允许残留但须知情)
|
|
471
|
+
|
|
472
|
+
**单行**(仅一行代码):行上写标签即可。
|
|
473
|
+
|
|
474
|
+
```kotlin
|
|
475
|
+
// MOCK: 用户列表假数据,接 UserRepository.list() 后删除
|
|
476
|
+
fun users() = listOf(User("张三"))
|
|
477
|
+
|
|
478
|
+
// TESTCODE: 本地跳过登录,联调完删除
|
|
479
|
+
if (BuildConfig.DEBUG) return true
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
**多行 / 大段(≥2 行逻辑)强制包夹**——标签在前、`BEGIN`/`END` 成对,说明写在 `BEGIN` 行:
|
|
483
|
+
|
|
484
|
+
```text
|
|
485
|
+
// MOCK BEGIN: <说明 + 将来替换点>
|
|
486
|
+
... 多行假数据 / stub ...
|
|
487
|
+
// MOCK END
|
|
488
|
+
|
|
489
|
+
// TESTCODE BEGIN: <说明 + 移除条件>
|
|
490
|
+
... 多行调试 / 旁路 ...
|
|
491
|
+
// TESTCODE END
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
```kotlin
|
|
495
|
+
// ❌ 大段无包夹
|
|
496
|
+
fun loadHome(): HomeData {
|
|
497
|
+
val banners = listOf(Banner("a"), Banner("b"))
|
|
498
|
+
val user = User("张三")
|
|
499
|
+
return HomeData(banners, user)
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// ✅
|
|
503
|
+
// MOCK BEGIN: 首页假数据,接 HomeRepository.fetch 后删除
|
|
504
|
+
fun loadHome(): HomeData {
|
|
505
|
+
val banners = listOf(Banner("a"), Banner("b"))
|
|
506
|
+
val user = User("张三")
|
|
507
|
+
return HomeData(banners, user)
|
|
508
|
+
}
|
|
509
|
+
// MOCK END
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
```xml
|
|
513
|
+
<!-- MOCK BEGIN: 预览占位,接 CMS 后删除 -->
|
|
514
|
+
<TextView android:text="占位标题" />
|
|
515
|
+
<TextView android:text="占位副标题" />
|
|
516
|
+
<!-- MOCK END -->
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
AS 默认 TODO 窗主要扫 `TODO`;`TESTCODE`/`MOCK` 用全局搜索,或在 Settings → Editor → TODO 增加 pattern `\bTESTCODE\b.*`、`\bMOCK\b.*`。
|
|
520
|
+
|
|
437
521
|
### 2.10 Gradle 脚本注释(Groovy)
|
|
438
522
|
|
|
439
523
|
老项目的 `build.gradle` / `settings.gradle` 多用 **Groovy** 编写(新项目 Kotlin DSL `*.gradle.kts` 同理)。构建脚本是声明式配置,注释**只解释"为什么这样配",不复述配置项字面**。
|
|
@@ -533,7 +617,7 @@ public List<Order> findOrders(long userId) {
|
|
|
533
617
|
|
|
534
618
|
### 强制规则
|
|
535
619
|
|
|
536
|
-
- 公开方法 / 函数参数 ≤ **3 个**,超过则封装为 DTO / `data class`
|
|
620
|
+
- 公开方法 / 函数参数 ≤ **3 个**,超过则封装为 DTO / `data class`(封装出的 DTO **必须**遵守下文「数据实体类封装」)
|
|
537
621
|
- Kotlin 优先**命名参数 + 默认参数**代替方法重载
|
|
538
622
|
- 函数体不超过 **50 行**,超过则拆分
|
|
539
623
|
- 单文件不超过 **500 行**,超过则拆分模块
|
|
@@ -636,6 +720,146 @@ for (Order o : orders) {
|
|
|
636
720
|
}
|
|
637
721
|
```
|
|
638
722
|
|
|
723
|
+
### 数据实体类封装(强制)
|
|
724
|
+
|
|
725
|
+
**动机**:Java 一旦暴露 `public` 字段,调用方直接依赖字段名与访问方式;后续改为 `private` + getter 会破坏源码 / 二进制兼容。实体从一开始就封装,避免后期改结构成本。Kotlin 编译属性本就是 private 字段 + 访问器,规则与 Java 分写,禁止用 `@JvmField` 退化成 public 字段。
|
|
726
|
+
|
|
727
|
+
#### 适用范围
|
|
728
|
+
|
|
729
|
+
| 覆盖 | 不覆盖 |
|
|
730
|
+
| ---- | ------ |
|
|
731
|
+
| Model / Entity / DTO / VO / Bean 及同类数据载体 | Activity / Fragment / Adapter / ViewHolder / Repository / ViewModel 等非数据载体 |
|
|
732
|
+
| 含功能包内私有、`internal` 实体 | `enum`;仅含常量的 `object` / `Constants` 类 |
|
|
733
|
+
| 网络响应体、跨层传递的数据对象 | 纯 UI 状态若仅为页面内部临时结构且不跨层,可豁免(跨层则按实体处理) |
|
|
734
|
+
|
|
735
|
+
#### 共同要求
|
|
736
|
+
|
|
737
|
+
1. 字段 / 属性**不得**以 public 字段形式对外暴露(禁止 Java `public` 实例字段、禁止 Kotlin `@JvmField`)
|
|
738
|
+
2. 必须提供读取能力:Java `getXxx()`,Kotlin property 访问器
|
|
739
|
+
3. 必须有有意义的 `toString()`(能区分关键业务字段);禁止依赖 `Object` 默认 `ClassName@hash`
|
|
740
|
+
4. **不强制** `equals` / `hashCode`(集合去重 / Map key 场景由调用方按需补)
|
|
741
|
+
|
|
742
|
+
---
|
|
743
|
+
|
|
744
|
+
#### Java 规则
|
|
745
|
+
|
|
746
|
+
| 项 | 要求 |
|
|
747
|
+
| -- | ---- |
|
|
748
|
+
| 字段 | 必须 `private`;禁止 `public` / 包可见实例字段当实体 API |
|
|
749
|
+
| 访问器 | 提供 `getXxx()` / `setXxx()`;不可变实体可用构造注入 + 仅 getter |
|
|
750
|
+
| toString | `@Override public String toString()`,包含关键业务字段 |
|
|
751
|
+
| 注释 | 类级说明职责;每个 private 字段上 `/** */`(见 §2.6) |
|
|
752
|
+
|
|
753
|
+
```java
|
|
754
|
+
/**
|
|
755
|
+
* 用户信息实体。
|
|
756
|
+
*
|
|
757
|
+
* <p>字段私有 + getter/setter,避免 public 字段导致后续无法安全改结构。
|
|
758
|
+
*/
|
|
759
|
+
public class User {
|
|
760
|
+
/** 用户 ID,服务端分配,> 0 */
|
|
761
|
+
private long id;
|
|
762
|
+
/** 昵称,1-32 字符 */
|
|
763
|
+
private String name;
|
|
764
|
+
|
|
765
|
+
public long getId() {
|
|
766
|
+
return id;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
public void setId(long id) {
|
|
770
|
+
this.id = id;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
public String getName() {
|
|
774
|
+
return name;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
public void setName(String name) {
|
|
778
|
+
this.name = name;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
@Override
|
|
782
|
+
public String toString() {
|
|
783
|
+
return "User{id=" + id + ", name='" + name + "'}";
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
```java
|
|
789
|
+
// ❌ public 字段 — 调用方直接 .id,后期改 private 会大面积破坏
|
|
790
|
+
public class User {
|
|
791
|
+
public long id;
|
|
792
|
+
public String name;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// ❌ 有 private 字段但缺 toString / 缺访问器
|
|
796
|
+
public class User {
|
|
797
|
+
private long id;
|
|
798
|
+
// 无 getId,外部无法读;无 toString,日志只能看到 @hash
|
|
799
|
+
}
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
---
|
|
803
|
+
|
|
804
|
+
#### Kotlin 规则
|
|
805
|
+
|
|
806
|
+
| 项 | 要求 |
|
|
807
|
+
| -- | ---- |
|
|
808
|
+
| 优先写法 | **`data class` + `val`**(编译为 private 字段 + getter;`data class` 自带 `toString`) |
|
|
809
|
+
| 可变字段 | 确需可变用 `var`;仅允许类内改写时用 `private set` |
|
|
810
|
+
| 禁止 | `@JvmField`;Java 风格 public 字段;为 `data class` 再手写冗余 get/set(Java 互操作强制命名除外) |
|
|
811
|
+
| 非 data class | property 或 private 字段 + 访问器,**必须** `override fun toString()` |
|
|
812
|
+
| 注释 | 构造属性用 `@property`,与 §2.6 一致 |
|
|
813
|
+
|
|
814
|
+
```kotlin
|
|
815
|
+
/**
|
|
816
|
+
* 用户信息实体。
|
|
817
|
+
*
|
|
818
|
+
* @property id 用户 ID,服务端分配,> 0
|
|
819
|
+
* @property name 昵称,1-32 字符
|
|
820
|
+
*/
|
|
821
|
+
data class User(
|
|
822
|
+
val id: Long,
|
|
823
|
+
val name: String,
|
|
824
|
+
)
|
|
825
|
+
// data class 已生成 toString / componentN / copy;JVM 侧字段为 private + getter
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
```kotlin
|
|
829
|
+
/**
|
|
830
|
+
* 可编辑的草稿实体。
|
|
831
|
+
*
|
|
832
|
+
* 非 data class 时必须手写 toString;title 仅允许类内改写。
|
|
833
|
+
*/
|
|
834
|
+
class Draft {
|
|
835
|
+
var title: String = ""
|
|
836
|
+
private set
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* 更新草稿标题。
|
|
840
|
+
*
|
|
841
|
+
* @param value 新标题,调用方已做长度校验
|
|
842
|
+
*/
|
|
843
|
+
fun updateTitle(value: String) {
|
|
844
|
+
title = value
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
override fun toString(): String = "Draft(title=$title)"
|
|
848
|
+
}
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
```kotlin
|
|
852
|
+
// ❌ @JvmField 把属性暴露成 public 字段,与 Java public 字段同样难改
|
|
853
|
+
class User {
|
|
854
|
+
@JvmField
|
|
855
|
+
var id: Long = 0
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// ❌ 普通 class 实体无 toString — 日志只有类名@hash
|
|
859
|
+
class User(val id: Long, val name: String)
|
|
860
|
+
// ✅ 改为 data class User(...) 或 override fun toString()
|
|
861
|
+
```
|
|
862
|
+
|
|
639
863
|
### 包组织(按功能聚合)
|
|
640
864
|
|
|
641
865
|
**按功能聚合(package-by-feature),不按技术分层(package-by-layer)。**
|
|
@@ -743,6 +967,51 @@ val result = calculate(x)
|
|
|
743
967
|
|
|
744
968
|
## 八、常见反模式(禁止)
|
|
745
969
|
|
|
970
|
+
### 字符串空判断(强制)
|
|
971
|
+
|
|
972
|
+
判断字符串是否为空、是否有有效内容时,**禁止**用 `length()` 比较,必须用语义明确的 `isEmpty()` / `isNotEmpty()`(Kotlin 意图为「非空白」时优先 `isNotBlank()`)。
|
|
973
|
+
|
|
974
|
+
**强制规则**:
|
|
975
|
+
|
|
976
|
+
- **禁止** `s.length() > 0`、`s.length() == 0`、`s.length() != 0`、`s.trim().length() > 0` 等 `length` 判空写法
|
|
977
|
+
- **必须**用 `isEmpty()` / `!isEmpty()`(Java) 或 `isEmpty()` / `isNotEmpty()`(Kotlin)
|
|
978
|
+
- 需先去首尾空白再判是否有内容:Java `!s.trim().isEmpty()`;Kotlin `s.trim().isNotEmpty()` 或等价的 `s.isNotBlank()`
|
|
979
|
+
- 可空字符串仍先做 null 判断,再判空:`s != null && !s.trim().isEmpty()`(与 §三可空性一致)
|
|
980
|
+
|
|
981
|
+
```java
|
|
982
|
+
// ❌ 用 length 判「是否有有效内容」——语义弱、易被误读成「长度阈值」
|
|
983
|
+
public String resolveVideoType() {
|
|
984
|
+
if (videoType != null && videoType.trim().length() > 0) {
|
|
985
|
+
return videoType.trim();
|
|
986
|
+
}
|
|
987
|
+
if (type != null && type.trim().length() > 0) {
|
|
988
|
+
return type.trim();
|
|
989
|
+
}
|
|
990
|
+
return null;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
// ✅ 用 isEmpty 表达「非空」
|
|
994
|
+
public String resolveVideoType() {
|
|
995
|
+
if (videoType != null && !videoType.trim().isEmpty()) {
|
|
996
|
+
return videoType.trim();
|
|
997
|
+
}
|
|
998
|
+
if (type != null && !type.trim().isEmpty()) {
|
|
999
|
+
return type.trim();
|
|
1000
|
+
}
|
|
1001
|
+
return null;
|
|
1002
|
+
}
|
|
1003
|
+
```
|
|
1004
|
+
|
|
1005
|
+
```kotlin
|
|
1006
|
+
// ❌
|
|
1007
|
+
if (videoType != null && videoType.trim().length > 0) { ... }
|
|
1008
|
+
|
|
1009
|
+
// ✅
|
|
1010
|
+
if (!videoType.isNullOrBlank()) { ... }
|
|
1011
|
+
// 或需保留 trim 后的值时:
|
|
1012
|
+
val trimmed = videoType?.trim().orEmpty()
|
|
1013
|
+
if (trimmed.isNotEmpty()) { ... }
|
|
1014
|
+
```
|
|
746
1015
|
|
|
747
1016
|
| 反模式 | 正确做法 |
|
|
748
1017
|
| ----------------------------------------------------------------- | ------------------------------------------- |
|
|
@@ -761,6 +1030,9 @@ val result = calculate(x)
|
|
|
761
1030
|
| 硬编码颜色值 `#FF0000` | `@color/color_primary` |
|
|
762
1031
|
| 用户可见文案硬编码 | `@string/...` |
|
|
763
1032
|
| 单行 `if` / `for` / `while` / `do-while` 无 `{}`(Kotlin 表达式 `if` 除外) | 即使只一行也写 `{}`;详见 §四「控制流大括号」 |
|
|
1033
|
+
| Java 实体 `public` 实例字段 | `private` 字段 + `getXxx`/`setXxx` + `toString` |
|
|
1034
|
+
| Kotlin 实体 `@JvmField` / 无 `toString` 的普通 class 实体 | 优先 `data class` + `val`;或手写访问器 + `toString` |
|
|
1035
|
+
| `s.length() > 0` / `s.trim().length() > 0` 等用 length 判空 / 非空 | Java `!s.isEmpty()` / `!s.trim().isEmpty()`;Kotlin `s.isNotEmpty()` / `s.isNotBlank()`;详见本节「字符串空判断」 |
|
|
764
1036
|
|
|
765
1037
|
|
|
766
1038
|
## 九、代码自检(写代码时强制执行)
|
|
@@ -774,7 +1046,7 @@ val result = calculate(x)
|
|
|
774
1046
|
| 2 | 方法 / 函数(不分可见性)有 Javadoc / KDoc,含 `@param` / `@return` / `@throws`;一目了然的简单 getter / setter、测试方法可省 | ✓ |
|
|
775
1047
|
| 3 | Activity / Fragment 类注释包含入口、参数 key、返回结果 | ✓ |
|
|
776
1048
|
| 4 | 回调接口注明每个参数语义 + 触发线程 | ✓ |
|
|
777
|
-
| 5 | `data class` /
|
|
1049
|
+
| 5 | `data class` 属性 / Java 实体 private 字段 / 配置常量逐个 `@property` 或字段注释 | ✓ |
|
|
778
1050
|
| 6 | 复杂业务逻辑有"why"行内注释,关联 PRD / 需求号 | ✓ |
|
|
779
1051
|
| 7 | 注释全部中文,无中英混用,无敷衍式"获取 / 设置 / 处理" | ✓ |
|
|
780
1052
|
| 8 | 注释与代码同步更新,无过时注释 | ✓ |
|
|
@@ -787,10 +1059,13 @@ val result = calculate(x)
|
|
|
787
1059
|
| 15 | 无空 `catch` 块、无 `catch (Throwable)`、无 `e.printStackTrace()` | ✓ |
|
|
788
1060
|
| 16 | 嵌套不超过 3 层,函数体不超过 50 行,单文件不超过 500 行 | ✓ |
|
|
789
1061
|
| 17 | 资源命名遵守:layout 前缀(`activity_`* / `fragment_*` / `item_*`)、id 控件缩写(`tv_*` / `et_*` / `btn_*` / `rv_*` …)、drawable / selector 状态后缀(`_normal` / `_pressed` / `_disabled` …)、anim / menu / style / mipmap 命名,9-patch 带 `.9` 后缀 | ✓ |
|
|
790
|
-
| 18 | 无注释掉的代码块(垃圾代码)
|
|
1062
|
+
| 18 | 无注释掉的代码块(垃圾代码);业务 TODO 带责任人+日期;产品源码假数据/调试旁路带 `MOCK:` / `TESTCODE:` | ✓ |
|
|
791
1063
|
| 19 | `if` / `else` / `else if` / `for` / `while` / `do-while` 语句即使单行也带 `{}`(Kotlin 表达式 `if` 除外) | ✓ |
|
|
792
1064
|
| 20 | 新增类按**功能聚合**放对应功能包(`login/` / `order/`),不按 `activities/` / `models/` 分层横切;仅多功能共享才放 `common/` | ✓ |
|
|
793
1065
|
| 21 | Gradle 脚本(Groovy / kts):锁版本 / `exclude` / 自定义 task / 变体 / 关键魔法值有 why 注释,无复述式、无注释掉的配置块 | ✓ |
|
|
1066
|
+
| 22 | 数据实体(Model/DTO/VO/Bean 等):Java 字段 `private` + get/set + `toString`;Kotlin 优先 `data class`+`val`(自带 toString),禁止 `@JvmField`,非 data class 必须手写 `toString` | ✓ |
|
|
1067
|
+
| 23 | 字符串空判断用 `isEmpty` / `isNotEmpty` / `isNotBlank`,禁止 `length() > 0` / `== 0` / `!= 0` 及 `trim().length() > 0` 判空;详见 §八「字符串空判断」 | ✓ |
|
|
794
1068
|
|
|
795
1069
|
|
|
796
1070
|
**不执行自检就提交代码 = 违规。**
|
|
1071
|
+
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Docker
|
|
2
|
+
description: Docker 通用规则(镜像固定版本、容器内存上限、日志大小限制、配置变更重启姿势)
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# Docker 通用规则
|
|
@@ -69,3 +69,54 @@ services:
|
|
|
69
69
|
max-size: "10m"
|
|
70
70
|
max-file: "3"
|
|
71
71
|
```
|
|
72
|
+
|
|
73
|
+
## 三、配置变更重启姿势(env_file / environment / .env)
|
|
74
|
+
|
|
75
|
+
### 根因
|
|
76
|
+
|
|
77
|
+
`docker compose restart` 只重启**已存在的容器进程**,**不会重读** `env_file` / `environment` / `.env`。env 变量只在**容器创建时**注入容器配置;restart 沿用旧容器的旧环境,新 env 永远进不去。
|
|
78
|
+
|
|
79
|
+
### 现象(真实踩坑)
|
|
80
|
+
|
|
81
|
+
预览机改了 `.env` 的 `DOLPHINDB_FACTOR__PORT=18560`,用 `docker compose restart` 加载 → preview 容器一直拿不到新值,因子 provider 静默回退到主库 8848,功能"看起来通了"实际走错库。当时报"已验证"是错的——只验了隧道连通,没验 app 实际配置(`printenv`)。
|
|
82
|
+
|
|
83
|
+
release 环境没踩坑:deploy-bg 是 build 后 `up -d`,镜像变更触发容器重建,重建时重读了 env_file。
|
|
84
|
+
|
|
85
|
+
### 强制规则
|
|
86
|
+
|
|
87
|
+
**改了 env_file / environment / `.env` 后,必须重建容器,不能只 restart:**
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# 正确:重建容器,重读 env
|
|
91
|
+
docker compose up -d --force-recreate backend
|
|
92
|
+
|
|
93
|
+
# 或更精准:只重建受影响服务,不动依赖
|
|
94
|
+
docker compose up -d --force-recreate --no-deps backend
|
|
95
|
+
|
|
96
|
+
# 错误:restart 不重读 env,新配置永远不生效
|
|
97
|
+
docker compose restart backend
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 判断容器是否重建的速查
|
|
101
|
+
|
|
102
|
+
| 操作 | 容器是否重建 | env 是否重读 |
|
|
103
|
+
|------|------------|------------|
|
|
104
|
+
| `docker compose restart` | 否(仅重启进程) | **否** |
|
|
105
|
+
| `docker compose up -d`(镜像无变化) | 否 | 否 |
|
|
106
|
+
| `docker compose up -d`(镜像有变化) | 是 | 是 |
|
|
107
|
+
| `docker compose up -d --force-recreate` | 是 | 是 |
|
|
108
|
+
| `docker compose up -d --env-file .env.prod`(换了 env 文件) | 是 | 是 |
|
|
109
|
+
|
|
110
|
+
### 验证清单(改 env 后必跑)
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# 1. 确认容器内实际生效的 env(不是宿主机的 .env)
|
|
114
|
+
docker compose exec backend printenv | grep DOLPHINDB_FACTOR__
|
|
115
|
+
|
|
116
|
+
# 2. 不要只验连通性,要验 app 实际读到的配置
|
|
117
|
+
# 连通=隧道通,不代表 app 配置对
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 一句话
|
|
121
|
+
|
|
122
|
+
> 配置改了别 restart,`up -d --force-recreate`。验证别只看连通,`printenv` 看容器内真值。
|
|
@@ -8,7 +8,13 @@ paths:
|
|
|
8
8
|
|
|
9
9
|
# ArkUI / 工程 / 运行时 避坑
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
| 文件 | 层 |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `dwy-arkts-strict.md` | 语言语法(arkts-no-*) |
|
|
14
|
+
| **本文件** | 组件 API、V2 状态、资源、工程构建、设备/运行时 |
|
|
15
|
+
| `dwy-arkts-ui-design.md` | UI 设计与交互(弹层关闭、加载三态等事前约束) |
|
|
16
|
+
| `dwy-harmony-pitfalls.md` | 四栏踩坑归档 |
|
|
17
|
+
|
|
12
18
|
均为真机/DevEco 构建实测踩坑(编译期或运行期暴露,命令行 tsc 查不出)。
|
|
13
19
|
|
|
14
20
|
## 1. sys.symbol 图标名 ≠ SF Symbols 名,必须查鸿蒙清单逐个映射
|
|
@@ -191,3 +197,46 @@ $NODE $HVIGOR --mode module -p module=entry@default -p product=default -p pageTy
|
|
|
191
197
|
见 `dwy-arkts-strict.md` 第 9 条(cryptoFramework 签名规格 / 公钥 DER 格式 / TCPSocket 局域网)。
|
|
192
198
|
补充:手撸 HTTP/2 的 HPACK 全字面量是否被对端(如 grpc-netty)接受、华为 IAP 需 AGC 后台
|
|
193
199
|
配商品 + 真机华为账号、asset/Preferences 在不同设备的可用性,均真机才能定论。
|
|
200
|
+
|
|
201
|
+
## 11. assembleHap 未配 signingConfigs → unsigned.hap
|
|
202
|
+
|
|
203
|
+
- **现象**:`hvigorw assembleHap` 成功但日志 `Will skip sign 'hos_hap'`,产物 `entry-default-unsigned.hap`;真机拒装。
|
|
204
|
+
- **根因**:`build-profile.json5` 的 `signingConfigs` 为空。
|
|
205
|
+
- **正确做法**:DevEco → Project Structure → Signing Configs 自动签名写回工程;**模拟器**可装 unsigned;**真机**必须签名。
|
|
206
|
+
- **适用**:CLI / CI 打包。
|
|
207
|
+
|
|
208
|
+
## 12. 本地模拟器(HVD)命令行:`-hvd` + hdc `127.0.0.1:5555`
|
|
209
|
+
|
|
210
|
+
- **现象**:不知如何脱离 IDE 起模拟器、装 HAP。
|
|
211
|
+
- **正确做法**:
|
|
212
|
+
- 启动:`/Applications/DevEco-Studio.app/Contents/tools/emulator/Emulator -hvd "Pura 90"`(名见 `~/.Huawei/Emulator/deployed/*.ini`)。
|
|
213
|
+
- 设备:`hdc list targets` → 常见 `127.0.0.1:5555`。
|
|
214
|
+
- 安装:`hdc -t 127.0.0.1:5555 install entry/.../entry-default-unsigned.hap`。
|
|
215
|
+
- 启动:`hdc -t 127.0.0.1:5555 shell aa start -a EntryAbility -b <bundleName>`。
|
|
216
|
+
- **适用**:无 GUI / 脚本化调试。
|
|
217
|
+
|
|
218
|
+
## 13. 模拟器验不了局域网 TCP / mDNS / 设备发现
|
|
219
|
+
|
|
220
|
+
- **现象**:模拟器里 app 连不上局域网电视、ADB、mDNS 服务。
|
|
221
|
+
- **根因**:HVD 网络多为 NAT,**不是**与电脑同 Wi-Fi 的 peer;模拟器「代理设置」只影响 HTTP 出网,**不能**桥接局域网。
|
|
222
|
+
- **正确做法**:依赖局域网原始 TCP / mDNS 的链路(ADB 5555、插件 28100、无线调试配对)必须 **鸿蒙真机 + 与目标设备同 Wi-Fi**。模拟器只做 UI / 导航 / 无网逻辑。
|
|
223
|
+
- **适用**:任何局域网设备调试类 app。
|
|
224
|
+
|
|
225
|
+
## 14. ScanKit `generateBarcode` 在模拟器常失败
|
|
226
|
+
|
|
227
|
+
- **现象**:二维码区域一直 spinner / 空白,业务 payload(如配对码数字)已生成。
|
|
228
|
+
- **根因**:`@kit.ScanKit` 的 `generateBarcode.createBarcode` 在 HVD 或部分镜像不可用。
|
|
229
|
+
- **正确做法**:
|
|
230
|
+
1. 调用时显式 `backgroundColor` / `pixelMapColor` / `margin`。
|
|
231
|
+
2. `catch` 后 **纯逻辑矩阵兜底**(自研或库 → `image.createPixelMap` RGBA),保证有图。
|
|
232
|
+
3. UI:仅生成中 spinner;失败出文案,禁止永久 loading(见 `dwy-arkts-ui-design.md`)。
|
|
233
|
+
- **适用**:任何依赖出码展示的页面。
|
|
234
|
+
|
|
235
|
+
## 文件职责(与本目录其它规则)
|
|
236
|
+
|
|
237
|
+
| 文件 | 管什么 |
|
|
238
|
+
|---|---|
|
|
239
|
+
| `dwy-arkts-strict.md` | 语言:禁用语法、arkts-no-* |
|
|
240
|
+
| `dwy-arkts-ui-build.md`(本文件) | 组件 API、状态、资源、构建、运行时/设备坑 |
|
|
241
|
+
| `dwy-arkts-ui-design.md` | **UI 设计规范**(弹层/顶栏/加载态/图标语义,事前约束) |
|
|
242
|
+
| `dwy-harmony-pitfalls.md` | 踩坑四栏归档(现象/根因/做法/适用),新坑先记这里再回写规范 |
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: HarmonyOS ArkUI UI 设计与交互规范(弹层/顶栏/加载态/图标语义,事前约束,避免 bindSheet 重叠等坑)
|
|
3
|
+
paths:
|
|
4
|
+
- "**/*.ets"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# ArkUI UI 设计规范
|
|
8
|
+
|
|
9
|
+
与 `dwy-arkts-ui-build.md`(怎么编译/踩过哪些 API 坑)配套:本文件管 **长什么样、交互怎么关、加载怎么显**。
|
|
10
|
+
写页面 / sheet **先按本规范搭骨架**,再写业务。踩到新 UI 坑:先记 `dwy-harmony-pitfalls.md`,再回写本文件。
|
|
11
|
+
|
|
12
|
+
## 1. 分层约定
|
|
13
|
+
|
|
14
|
+
| 层 | 职责 | 典型 API |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| 系统 chrome | 系统提供的关闭/拖拽指示 | `bindSheet` 的 `showClose`、下拉关闭 |
|
|
17
|
+
| 内容顶栏 | 标题 + 业务操作 +(可选)自绘关闭 | `SheetHeader` / 自绘 `Row` |
|
|
18
|
+
| 内容区 | 表单、列表、图 | 业务组件 |
|
|
19
|
+
|
|
20
|
+
**硬规则:系统关闭钮与内容自绘「关弹层」× 禁止同时出现。**
|
|
21
|
+
|
|
22
|
+
## 2. bindSheet 关闭策略(二选一)
|
|
23
|
+
|
|
24
|
+
### 2.1 模式 A:自绘关闭(工具页 / 表单 / 顶栏有右侧操作)
|
|
25
|
+
|
|
26
|
+
适用:Shell、进程、性能、调试、代理、录屏、快捷指令、设备编辑、**配对弹层**、设备信息(有「复制全部」等)。
|
|
27
|
+
|
|
28
|
+
```ets
|
|
29
|
+
.bindSheet(this.open, this.content(), {
|
|
30
|
+
detents: [SheetSize.LARGE],
|
|
31
|
+
backgroundColor: Palette.device,
|
|
32
|
+
showClose: false, // 必须关系统 ×
|
|
33
|
+
onDisappear: () => { this.open = false; },
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
@Builder
|
|
37
|
+
content(): void {
|
|
38
|
+
FooPage({ onClose: () => { this.open = false; } })
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
内容顶栏结构(从左到右):
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
[ 标题(layoutWeight 1,单行省略) ] [ 可选业务按钮 ] [ 关闭 × ]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- 关闭用 `sys.symbol.xmark`,固定触控约 `36×36`,勿与分段按钮同一 `Row` 抢宽。
|
|
49
|
+
- 分段 / Tab 切换放在 **顶栏下一行**,整行 `width('100%')`,不得伸进系统 chrome 区域。
|
|
50
|
+
|
|
51
|
+
### 2.2 模式 B:仅系统关闭(纯浏览 / 轻列表)
|
|
52
|
+
|
|
53
|
+
适用:语言选择、截图预览、无业务顶栏操作的列表。
|
|
54
|
+
|
|
55
|
+
```ets
|
|
56
|
+
.bindSheet(this.open, this.content(), {
|
|
57
|
+
showClose: true,
|
|
58
|
+
onDisappear: () => { this.open = false; },
|
|
59
|
+
})
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- 内容 **禁止** 再画关闭 ×。
|
|
63
|
+
- 顶栏右侧 **禁止** 放会与系统 × 重叠的控件(可放在内容区下方或用「完成」文字按钮在底部)。
|
|
64
|
+
|
|
65
|
+
### 2.3 禁止
|
|
66
|
+
|
|
67
|
+
| 禁止 | 原因 |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `showClose: true` + `SheetHeader` / 自绘 × | 双 × 重叠 |
|
|
70
|
+
| `showClose` 省略 + 自绘 × | 默认常带系统 ×,仍重叠 |
|
|
71
|
+
| 系统 × 与「新增 / 复制全部 / 分段 Tab」同一视觉行 | 贴边、难点 |
|
|
72
|
+
| 关闭回调空实现(`onClose` 未注入) | × 点了无反应 |
|
|
73
|
+
|
|
74
|
+
## 3. 图标语义(禁止混用)
|
|
75
|
+
|
|
76
|
+
| 语义 | 推荐符号 | 禁止 |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| 关弹层 | `xmark`(顶栏) | 与「清空」共用同一位置无说明 |
|
|
79
|
+
| 清空输入 | `xmark_circle_fill`(输入框旁) | 当成关 sheet |
|
|
80
|
+
| 返回上一页 | `chevron_left`(`PageHeaderBar`) | 用 × 表示返回 |
|
|
81
|
+
| 删除 | `trash` | 用 × 表示删除条目 |
|
|
82
|
+
|
|
83
|
+
输入弹层(键盘):**关 sheet 用模式 B(系统 ×)**;清空用输入框旁圆形 ×,注释写明「清空非关闭」。
|
|
84
|
+
|
|
85
|
+
## 4. 加载与空态(禁止永久 spinner)
|
|
86
|
+
|
|
87
|
+
异步出图 / 出列表必须三态:
|
|
88
|
+
|
|
89
|
+
| 状态 | UI |
|
|
90
|
+
|---|---|
|
|
91
|
+
| 加载中 | `LoadingProgress`(限在固定占位区域内) |
|
|
92
|
+
| 成功 | 内容(图 / 列表) |
|
|
93
|
+
| 失败 | 文案说明 + 可选重试;**禁止**继续转圈 |
|
|
94
|
+
|
|
95
|
+
二维码 / 图片:
|
|
96
|
+
|
|
97
|
+
1. 优先系统能力(如 ScanKit)。
|
|
98
|
+
2. 失败必须有 **可见兜底**(纯逻辑绘制 / 占位文案),不能空白。
|
|
99
|
+
3. 占位区 **固定宽高**,避免生成前后布局跳动。
|
|
100
|
+
|
|
101
|
+
## 5. 顶栏与安全区
|
|
102
|
+
|
|
103
|
+
- **Push 页**:`PageHeaderBar`(返回 + 标题 + trailing),前景在安全区内。
|
|
104
|
+
- **Sheet**:见 §2;全屏背景可用,主交互勿进系统手势死角。
|
|
105
|
+
- 标题:`maxLines(1)` + `TextOverflow.Ellipsis`,避免长文案挤掉按钮。
|
|
106
|
+
- 触控目标:主要按钮高度建议 ≥ 40;图标按钮约 36×36。
|
|
107
|
+
|
|
108
|
+
## 6. 布局与间距(基线)
|
|
109
|
+
|
|
110
|
+
- 页面水平 padding 统一 **16 / 20**(工具页内容区常用 16–20)。
|
|
111
|
+
- 卡片圆角与描边走 **设计 token**(如 `Palette.surface2` + `hairline`),禁止业务页散落硬编码色。
|
|
112
|
+
- 列表/宫格:用 `List` / `Grid` + 间距系统,不用绝对 `offset` 拼主布局。
|
|
113
|
+
- 固定视觉比例控件(二维码、D-pad)可用固定边长,**外层容器仍自适应宽度**。
|
|
114
|
+
|
|
115
|
+
## 7. 颜色与动效
|
|
116
|
+
|
|
117
|
+
- 颜色只从 `Palette`(或项目 token)取,禁止裸 `0xFF...` 散落业务页(生成图 RGBA 缓冲区除外)。
|
|
118
|
+
- 动效优先项目统一 spring / 系统默认;新增动画参数与现有 `Motion` 一致。
|
|
119
|
+
- 强调色用于主按钮;关闭/次要操作用 `Palette.sub`,删除用 `Palette.red`。
|
|
120
|
+
|
|
121
|
+
## 8. 文案与国际化
|
|
122
|
+
|
|
123
|
+
- 所有用户可见文案走 `loc('key')` + 资源表,禁止硬编码中文/英文(调试日志除外)。
|
|
124
|
+
- 新 key 至少补齐 **开发语言 + en**;其它语言可后续补。
|
|
125
|
+
|
|
126
|
+
## 9. 自检清单(PR / 提交前)
|
|
127
|
+
|
|
128
|
+
- [ ] 每个 `bindSheet` 已显式 `showClose: true` 或 `false`(不省略)。
|
|
129
|
+
- [ ] 自绘 × 的 sheet 已 `showClose: false` 且 `onClose` 接通。
|
|
130
|
+
- [ ] 系统 × 的 sheet 内容无第二颗关闭钮、右侧无抢位控件。
|
|
131
|
+
- [ ] 异步区有失败态,无永久 spinner。
|
|
132
|
+
- [ ] 出码/出图有 ScanKit 失败兜底(若依赖)。
|
|
133
|
+
- [ ] 图标名在 `id_defined.json` 存在(见 ui-build §1)。
|
|
134
|
+
- [ ] 文案全部 `loc`。
|
|
135
|
+
|
|
136
|
+
## 10. 与 iOS 对照时注意
|
|
137
|
+
|
|
138
|
+
- iOS `sheet` + 导航栏 toolbar 关闭 ≠ 鸿蒙默认 `showClose`;移植时 **重新选 §2 模式**,不要两端各画一套再叠系统。
|
|
139
|
+
- SF Symbols 名不能直接当 `sys.symbol`(见 ui-build §1)。
|