create-dwy 0.7.1 → 0.9.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 (96) hide show
  1. package/package.json +1 -1
  2. package/src/create.js +50 -3
  3. package/src/sync.js +228 -130
  4. package/src/utils.js +4 -0
  5. package/templates/claude-global/CLAUDE.md +81 -6
  6. package/templates/claude-global/rules/dwy-postgres.md +89 -0
  7. package/templates/claude-global/rules/dwy-python-backend.md +492 -0
  8. package/templates/claude-global/rules/dwy-python-core.md +94 -634
  9. package/templates/claude-global/rules/dwy-python-testing.md +115 -13
  10. package/templates/claude-global/rules/dwy-redis.md +88 -0
  11. package/templates/claude-global/rules/dwy-vue-core.md +341 -645
  12. package/templates/claude-global/rules/dwy-vue-pinia.md +47 -34
  13. package/templates/claude-global/rules/dwy-vue-testing.md +120 -55
  14. package/templates/claude-global/skills/dwy-deploy-audit/references/checks-network.md +1 -1
  15. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_nginx.sh +1 -1
  16. package/templates/claude-global/skills/dwy-dolphindb/SKILL.md +22 -15
  17. package/templates/claude-global/skills/dwy-dolphindb/evals/evals.json +23 -0
  18. package/templates/claude-global/skills/dwy-dolphindb/references/dolphindb-rules.md +100 -1
  19. package/templates/claude-global/skills/dwy-ekit/SKILL.md +142 -276
  20. package/templates/claude-global/skills/dwy-eui/SKILL.md +264 -182
  21. package/templates/claude-global/skills/dwy-fullstack-scaffold/SKILL.md +117 -129
  22. package/templates/claude-global/skills/dwy-git-commit/SKILL.md +125 -0
  23. package/templates/claude-global/skills/dwy-publish/SKILL.md +1 -1
  24. package/templates/claude-global/{rules/dwy-tech-stack.md → skills/dwy-tech-stack/SKILL.md} +4 -3
  25. package/templates/project/fullstack-monorepo/CLAUDE.md.hbs +81 -0
  26. package/templates/project/fullstack-monorepo/backend/.python-version +1 -0
  27. package/templates/project/fullstack-monorepo/backend/CLAUDE.md.hbs +68 -0
  28. package/templates/project/fullstack-monorepo/backend/Dockerfile.dev +23 -0
  29. package/templates/project/fullstack-monorepo/backend/alembic/env.py.hbs +68 -0
  30. package/templates/project/fullstack-monorepo/backend/alembic/script.py.mako +26 -0
  31. package/templates/project/fullstack-monorepo/backend/alembic.ini.hbs +43 -0
  32. package/templates/project/fullstack-monorepo/backend/packages/dwy-shared/pyproject.toml +16 -0
  33. package/templates/project/fullstack-monorepo/backend/packages/dwy-shared/src/dwy_shared/__init__.py +12 -0
  34. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/pyproject.toml.hbs +20 -0
  35. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/__init__.py.hbs +40 -0
  36. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/config.py +9 -0
  37. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/models.py.hbs +17 -0
  38. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/protocols.py +14 -0
  39. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/router.py.hbs +22 -0
  40. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/schemas.py +21 -0
  41. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/service.py +11 -0
  42. package/templates/project/fullstack-monorepo/backend/pyproject.toml.hbs +84 -0
  43. package/templates/project/fullstack-monorepo/backend/src/app/__init__.py +3 -0
  44. package/templates/project/fullstack-monorepo/backend/src/app/config.py.hbs +21 -0
  45. package/templates/project/fullstack-monorepo/backend/src/app/exceptions.py +26 -0
  46. package/templates/project/fullstack-monorepo/backend/src/app/factories.py +16 -0
  47. package/templates/project/fullstack-monorepo/backend/src/app/infra/__init__.py +1 -0
  48. package/templates/project/fullstack-monorepo/backend/src/app/main.py.hbs +65 -0
  49. package/templates/project/fullstack-monorepo/backend/src/app/middleware/__init__.py +1 -0
  50. package/templates/project/fullstack-monorepo/backend/tests/__init__.py +0 -0
  51. package/templates/project/fullstack-monorepo/backend/tests/conftest.py.hbs +42 -0
  52. package/templates/project/fullstack-monorepo/dev.sh.hbs +83 -0
  53. package/templates/project/fullstack-monorepo/docker-compose.dev.yml.hbs +36 -0
  54. package/templates/project/fullstack-monorepo/frontend/CLAUDE.md.hbs +35 -0
  55. package/templates/project/fullstack-monorepo/frontend/Dockerfile +18 -0
  56. package/templates/project/fullstack-monorepo/frontend/apps/web/index.html.hbs +13 -0
  57. package/templates/project/fullstack-monorepo/frontend/apps/web/package.json.hbs +31 -0
  58. package/templates/project/fullstack-monorepo/frontend/apps/web/src/App.vue.hbs +10 -0
  59. package/templates/project/fullstack-monorepo/frontend/apps/web/src/api/client.ts.hbs +11 -0
  60. package/templates/project/fullstack-monorepo/frontend/apps/web/src/features/{{initialDomain}}/.gitkeep +0 -0
  61. package/templates/project/fullstack-monorepo/frontend/apps/web/src/index.css +12 -0
  62. package/templates/project/fullstack-monorepo/frontend/apps/web/src/main.ts +17 -0
  63. package/templates/project/fullstack-monorepo/frontend/apps/web/src/router/index.ts.hbs +24 -0
  64. package/templates/project/fullstack-monorepo/frontend/apps/web/src/stores/.gitkeep +0 -0
  65. package/templates/project/fullstack-monorepo/frontend/apps/web/src/types/.gitkeep +0 -0
  66. package/templates/project/fullstack-monorepo/frontend/apps/web/src/views/HomeView.vue.hbs +36 -0
  67. package/templates/project/fullstack-monorepo/frontend/apps/web/tsconfig.json +7 -0
  68. package/templates/project/fullstack-monorepo/frontend/apps/web/vite.config.ts.hbs +27 -0
  69. package/templates/project/fullstack-monorepo/frontend/nginx.conf +11 -0
  70. package/templates/project/fullstack-monorepo/frontend/package.json.hbs +13 -0
  71. package/templates/project/fullstack-monorepo/frontend/packages/core/package.json.hbs +15 -0
  72. package/templates/project/fullstack-monorepo/frontend/packages/core/src/index.ts +3 -0
  73. package/templates/project/fullstack-monorepo/frontend/packages/features/{{initialDomain}}/package.json.hbs +14 -0
  74. package/templates/project/fullstack-monorepo/frontend/packages/features/{{initialDomain}}/src/index.ts.hbs +16 -0
  75. package/templates/project/fullstack-monorepo/frontend/packages/features/{{initialDomain}}/src/pages/IndexPage.vue.hbs +9 -0
  76. package/templates/project/fullstack-monorepo/frontend/packages/ui/package.json.hbs +15 -0
  77. package/templates/project/fullstack-monorepo/frontend/packages/ui/src/index.ts +3 -0
  78. package/templates/project/fullstack-monorepo/frontend/pnpm-workspace.yaml.hbs +23 -0
  79. package/templates/project/fullstack-monorepo/frontend/tsconfig.base.json.hbs +23 -0
  80. package/templates/claude-global/rules/dwy-api-design.md +0 -110
  81. package/templates/claude-global/rules/dwy-git-commit-convention.md +0 -82
  82. package/templates/claude-global/rules/dwy-git-security.md +0 -53
  83. package/templates/claude-global/rules/dwy-payload-limits.md +0 -186
  84. package/templates/claude-global/rules/dwy-prefer-open-source.md +0 -32
  85. package/templates/claude-global/rules/dwy-project-structure.md +0 -181
  86. package/templates/claude-global/rules/dwy-python-fastapi.md +0 -272
  87. package/templates/claude-global/rules/dwy-python-orm.md +0 -61
  88. package/templates/claude-global/rules/dwy-python-security.md +0 -636
  89. package/templates/claude-global/rules/dwy-server-security.md +0 -518
  90. package/templates/claude-global/rules/dwy-vue-api.md +0 -146
  91. package/templates/claude-global/skills/dwy-ekit/references/data.md +0 -135
  92. package/templates/claude-global/skills/dwy-ekit/references/form.md +0 -68
  93. package/templates/claude-global/skills/dwy-ekit/references/request.md +0 -183
  94. package/templates/claude-global/skills/dwy-ekit/references/ui.md +0 -109
  95. package/templates/claude-global/skills/dwy-vue-core/SKILL.md +0 -890
  96. /package/templates/{claude-global/commands → project/fullstack-monorepo/backend/alembic/versions}/.gitkeep +0 -0
@@ -1,230 +1,191 @@
1
1
  ---
2
2
  name: dwy-eui
3
- description: "@dwydev/eui Vue 3 组件库速查。当用户在使用 Vue 3 构建页面、选择 UI 组件、查询组件 API、写表单/表格/弹层/导航、配置主题或国际化、使用中后台或落地页设计规范时,**必须**使用此 skill。即使用户没有明确说'eui',只要涉及 Vue 3 组件选型、页面布局、表单设计、数据展示、弹层交互、主题切换,也应触发。"
3
+ description: "@dwydev/eui Vue 3 组件库使用指南。当用户在使用 Vue 3 构建页面、选择 UI 组件、查询组件 API、写表单/表格/弹层/导航、配置主题或国际化、使用中后台或落地页设计规范时,**必须**使用此 skill。即使用户没有明确说 'eui',只要涉及 Vue 3 组件选型、页面布局、表单设计、数据展示、弹层交互、主题切换,也应触发。"
4
+ eui_baseline_version: "2.1.0"
4
5
  ---
5
6
 
6
- # @dwydev/eui 组件速查
7
+ # @dwydev/eui 组件库使用指南
7
8
 
8
- 基于 Reka-ui 原语层 + shadcn-vue 设计风格 + Element Plus 式 API 的 Vue 3 组件库。
9
+ Vue 3 组件库:Reka-ui 原语层 + shadcn-vue 设计风格 + Element Plus 式 API + Tailwind CSS 4。
9
10
 
10
- ## 集成指南
11
+ 本 skill 的索引信息基于 EUI **2.1.0**。消费方项目实际版本可能不同 — 见 [版本兼容规则](#版本兼容规则)。
11
12
 
12
- 新项目集成 EUI 时,读取 `references/eui-integration-guide.md`,包含完整的安装、Vite 配置、样式引入、组件注册、主题切换等步骤。
13
+ ---
13
14
 
14
- ## 设计风格规范
15
+ ## 集成与设计规范
15
16
 
16
- - **中后台页面**:读取 `references/eui-design-guide.md`,包含颜色系统、布局规范、排版规范、组件使用规范、交互规范等。
17
- - **落地页/营销页**:读取 `references/eui-landing-design-guide.md`,包含 Hero、功能展示、社会证明、定价、FAQ 等 Section 模板和动画规范。
17
+ | 场景 | 读取文件 |
18
+ |------|---------|
19
+ | 新项目集成 EUI | `references/eui-integration-guide.md` |
20
+ | 中后台页面设计规范 | `references/eui-design-guide.md` |
21
+ | 落地页/营销页设计规范 | `references/eui-landing-design-guide.md` |
18
22
 
19
23
  ---
20
24
 
21
- ## 命名约定
25
+ ## 查 API 标准动作(核心:每次用组件前都做)
22
26
 
23
- - 组件前缀 `E`:`EButton`, `EInput`, `EDialog`
24
- - Props 类型:`E{Name}Props`(如 `EButtonProps`)
25
- - Events 类型:`E{Name}Emits`(如 `EInputEmits`)
26
- - CVA 变体:`{name}Variants`(如 `buttonVariants`)
27
- - 样式合并工具:`cn()` = clsx + tailwind-merge
28
- - 尺寸统一类型:`Size = 'sm' | 'default' | 'lg'`
27
+ EUI 有 87 个组件目录、117 个对外组件。**本文档不再镜像 props/emits 列表** —— 因为它们会随版本漂移。AI 想用某个组件时,按下面顺序拿到精确 API:
28
+
29
+ ### 第一步:定位 EUI 真实版本
30
+
31
+ 读消费方项目的 `package.json`,找 `dependencies["@dwydev/eui"]` 或 `peerDependencies["@dwydev/eui"]`。这个版本号才是 AI 写代码的依据,不是 skill frontmatter 里的 baseline。
32
+
33
+ ### 第二步:读 component-manifest.json(一次拿组件地图)
34
+
35
+ 从 EUI 2.1.0 起,npm 包带一份组件清单:
36
+
37
+ ```
38
+ <project-root>/node_modules/@dwydev/eui/dist/component-manifest.json
39
+ ```
40
+
41
+ 结构(精简示例):
42
+ ```json
43
+ {
44
+ "version": "2.1.0",
45
+ "componentToDir": { "EButton": "button", "ECommandInput": "command" },
46
+ "directories": {
47
+ "button": { "types": "components/button/types.d.ts", "components": ["EButton"] },
48
+ "command": { "types": null, "components": ["ECommand", "ECommandInput", "..."] }
49
+ },
50
+ "composables": ["useMessage", "useTheme", "..."]
51
+ }
52
+ ```
29
53
 
30
- ## 查阅完整 API(按需读取源码)
54
+ 用法:
55
+ - 知道组件名(如 `EButton`) → 查 `componentToDir["EButton"]` 拿到目录 `"button"`
56
+ - 查 `directories["button"].types` 拿到类型文件相对路径
57
+ - 拼接:`<project-root>/node_modules/@dwydev/eui/dist/{types}` 就是要读的 .d.ts
31
58
 
32
- 当需要某个组件的精确 props/slots/events/类型定义时,**必须**读取对应源码文件:
59
+ manifest 不存在的回退:
60
+ - 消费方装的是 EUI < 2.1.0(旧版本没有 manifest) → 直接走第三步用约定路径
61
+ - 仓库无 node_modules(裸 monorepo / 未 install) → 走第三步的 dwy-shared 路径
62
+
63
+ ### 第三步:读组件 types.d.ts(精确 props + emits)
64
+
65
+ 按存在性回退:
33
66
 
34
67
  ```
35
- frontend/eui/src/components/{component-name}/types.ts
36
- frontend/eui/src/components/{component-name}/EName.vue # 模板和逻辑
68
+ a. 优先:<project-root>/node_modules/@dwydev/eui/dist/components/{kebab}/types.d.ts
69
+ —— 下游消费方默认场景,含完整 props + emits + JSDoc 注释
70
+
71
+ b. 次选:<dwy-shared-root>/frontend/eui/src/components/{kebab}/types.ts
72
+ —— 仅当在 dwy-shared monorepo 内或并列 clone 时可用,等价信息
73
+
74
+ c. 都拿不到 → 退到本文档下方的 [组件目录索引](#组件目录索引)(粗略,仅做导航)
37
75
  ```
38
76
 
39
- 组件目录清单(89 个组件):`frontend/eui/src/components/` 下包含 button、input、table、dialog、date-picker、chart、admin-layout、ai-chat 等。不确定组件名时,先 `ls frontend/eui/src/components/` 查看。
77
+ `{kebab}` 是目录名规则:组件名去 `E` 前缀后转 kebab-case。
78
+ - `EButton` → `button`
79
+ - `EDatePicker` → `date-picker`
80
+ - `EAdminLayout` → `admin-layout`
81
+ - `EAIChat` → `ai-chat`(连续大写视为整体)
82
+
83
+ **不确定目录名时**:`ls node_modules/@dwydev/eui/dist/components/` 或 `ls frontend/eui/src/components/`,**不要靠猜**。
84
+
85
+ ### 第四步:slots 看 .vue 模板(不在 .d.ts 里)
86
+
87
+ vue-tsc 输出的 `.d.ts` 中,slots 类型大多被擦平成 `any`。需要 slot 用法(默认插槽、具名插槽、作用域插槽)时,读源码 `.vue` 文件,搜索 `<slot` 看模板里实际定义。
88
+
89
+ - node_modules 路径下 `.vue` 文件**不存在**(只有 .d.ts),slots 必须回 dwy-shared 源码看
90
+ - 拿不到源码时:参考 reka-ui / shadcn-vue 的同名组件 slots 规范,多数 EUI 组件直接转发
91
+
92
+ ### 第五步:冲突时永远信 node_modules
93
+
94
+ 当本 SKILL.md 的描述与消费方项目的 node_modules `.d.ts` 不一致:**无条件以 node_modules 为准**。本文档是导航与心智模型,不是 API 真相。
40
95
 
41
96
  ---
42
97
 
43
- ## 组件索引
44
-
45
- ### 基础组件
46
-
47
- | 组件 | 用途 | 关键 Props |
48
- |------|------|-----------|
49
- | EButton | 按钮 | variant(default/destructive/outline/secondary/ghost/link), size(default/sm/lg/icon), loading, disabled |
50
- | EBadge | 标签徽章 | variant(default/secondary/destructive/outline) |
51
- | EAlert | 警告提示 | variant(default/destructive), title, description, closable |
52
- | ECard | 卡片容器 | title, description |
53
- | ELabel | 标签文本 | for |
54
- | ESeparator | 分隔线 | orientation(horizontal/vertical) |
55
- | ETypography | 排版文本 | variant, as |
56
- | EKbd | 键盘按键展示 | — |
57
- | ESpinner | 加载动画 | size(sm/default/lg) |
58
- | EProgress | 进度条 | modelValue(0-100) |
59
- | ESkeleton | 骨架屏 | — |
60
- | EEmpty | 空状态 | title, description, icon |
61
- | EAvatar | 头像 | src, alt, fallback, size |
62
- | EImage | 图片 | src, alt, fit, lazy, fallback, preview |
63
-
64
- ### 表单组件
65
-
66
- | 组件 | 用途 | 关键 Props |
67
- |------|------|-----------|
68
- | EInput | 输入框 | v-model, type, placeholder, size, clearable, showPassword, disabled, readonly, maxlength, showWordLimit |
69
- | ETextarea | 多行输入 | v-model, placeholder, rows, autoResize, maxlength, disabled, showWordLimit, minRows, maxRows |
70
- | ENumberField | 数字输入 | v-model, min, max, step, size, disabled, precision, controlsPosition, placeholder, readonly |
71
- | ESelect | 下拉选择 | v-model, options(Option[]), placeholder, clearable, size, disabled, filterable, multiple, collapseTags, remote, remoteMethod, loading。**注意:option.value 不能为空字符串**,reka-ui 不支持 |
72
- | ENativeSelect | 原生 select | v-model, options(SelectOption[]), placeholder, disabled |
73
- | ECombobox | 组合框 | v-model, options(Option[]), placeholder, emptyText, disabled |
74
- | EAutocomplete | 自动补全 | v-model, fetchSuggestions(async fn), debounce, placeholder |
75
- | ECheckbox | 复选框 | v-model, label, disabled, indeterminate, options(Option[]), direction(horizontal/vertical), border |
76
- | ERadio | 单选组 | v-model, options(Option[]), direction(horizontal/vertical), disabled, optionType(default/button), border, size |
77
- | ESwitch | 开关 | v-model, label, size, disabled |
78
- | ETagsInput | 标签输入 | v-model(string[]), placeholder, max, size, disabled |
79
- | EDatePicker | 日期选择 | v-model, type(date/daterange/month/year), placeholder, startPlaceholder, endPlaceholder, rangeSeparator, format, clearable, disabled, disabledDate, shortcuts(DatePickerShortcut[]) |
80
- | ETimePicker | 时间选择 | v-model, placeholder, format, hourStep, minuteStep, disabled |
81
- | EColorPicker | 颜色选择 | v-model, presets(string[]), showAlpha, disabled |
82
- | ERate | 评分 | v-model, max, allowHalf, showText, disabled |
83
- | ESlider | 滑块 | v-model(number[]), min, max, step, orientation, disabled |
84
- | ECascader | 级联选择 | v-model, options(CascaderOption[]), placeholder, filterable, clearable, lazy, loadFn, multiple, collapseTags |
85
- | ETreeSelect | 树选择 | v-model, data(TreeNode[]), placeholder, multiple, checkable, disabled |
86
- | EMention | @提及输入 | v-model, options(MentionOption[]), prefix, loading, placeholder |
87
- | EInputOTP | OTP 验证码 | v-model, length, disabled, placeholder |
88
- | EPinInput | PIN 输入 | v-model(string[]), length, mask, otp, type(text/number) |
89
- | EUpload | 文件上传 | v-model(UploadFile[]), action, accept, multiple, limit, listType(text/picture/picture-card), drag, beforeUpload, autoUpload, headers, withCredentials |
90
- | ETransfer | 穿梭框 | v-model, data(TransferItem[]), filterable, titles([string, string]) |
91
- | EForm | 表单容器 | model, rules(Zod/FormRule[]), labelWidth, labelPosition(left/right/top), size, disabled, inline |
92
- | EFormItem | 表单项 | (配合 EForm 使用) |
93
- | EField | 字段布局 | orientation(vertical/horizontal/responsive), invalid |
94
- | EInputGroup | 输入组 | 子组件 EInputGroupAddon(align) |
95
-
96
- #### 表单强制约束
97
-
98
- **禁止使用原生 `<form>` 标签,所有表单必须使用 `<EForm>` 组件。** EForm 内置 vee-validate 校验、provide/inject 上下文传递、统一的 label 布局和 reset/validate API,原生 `<form>` 无法与 EUI 表单体系集成。
98
+ ## 版本兼容规则
99
99
 
100
- ### 数据展示
100
+ - 本 skill `eui_baseline_version: 2.1.0`,组件索引、composables 列表、踩坑提示都基于这个版本
101
+ - 消费方项目用的是不同版本时(无论更新或更旧),**必须按"查 API 标准动作"流程读 .d.ts**,不要默认本文档准确
102
+ - EUI < 2.1.0 没有 `component-manifest.json`:直接走第三步的 types.d.ts 约定路径
103
+ - 主版本号变更(1.x → 2.x、2.x → 3.x)时,本文档的索引可能完全失效:必须先 `ls node_modules/@dwydev/eui/dist/components/` 重建认知
101
104
 
102
- | 组件 | 用途 | 关键 Props |
103
- |------|------|-----------|
104
- | ETable | 表格 | data, columns(TableColumn[]), loading, rowKey, striped, bordered, selectable, selectedKeys, expandable, expandedRowKeys, rowClassName, showSummary, summaryMethod, virtual, virtualRowHeight, resizable |
105
- | EVirtualTable | 虚拟滚动表格 | columns(VirtualTableColumn[]), data, height, estimateRowHeight, rowKey, loading |
106
- | EDescriptions | 描述列表 | items(DescriptionItem[]), columns, bordered, title |
107
- | ETimeline | 时间线 | items(TimelineItem[]), reverse |
108
- | EStatistic | 统计数值 | title, value, prefix, suffix, precision |
109
- | ETree | 树形控件 | data(TreeNode[]), v-model, checkable, expandedKeys, defaultExpandAll, lazy, loadFn, draggable, filterMethod, filterQuery, checkStrictly |
110
- | ECalendar | 日历 | v-model, multiple, disabled, locale, minValue, maxValue |
111
- | ERangeCalendar | 日期范围日历 | v-model({start, end}), disabled, locale, minValue, maxValue |
112
- | EPagination | 分页 | v-model, total, pageSize, showSizeChanger, pageSizes, showTotal, jumper, layout, disabled |
113
- | EBreadcrumb | 面包屑 | items(BreadcrumbItem[]), separator |
105
+ ---
114
106
 
115
- ### 弹层与反馈
107
+ ## 命名约定
108
+
109
+ - 组件前缀 `E`:`EButton`、`EInput`、`EDialog`
110
+ - Props 类型:`E{Name}Props`(如 `EButtonProps`)
111
+ - Events 类型:`E{Name}Emits`(如 `EInputEmits`)
112
+ - CVA 变体:`{name}Variants`(如 `buttonVariants`)
113
+ - 样式合并工具:`cn()` = clsx + tailwind-merge
114
+ - 尺寸统一类型:`Size = 'sm' | 'default' | 'lg'`
115
+ - 复合组件用 `provide/inject` 共享状态,子组件目录与主组件同处(如 `command/` 下含 ECommand、ECommandInput、ECommandList...)
116
116
 
117
- | 组件 | 用途 | 关键 Props |
118
- |------|------|-----------|
119
- | EDialog | 对话框 | v-model:open, title, description, showClose, maxWidth, draggable, closeOnClickModal, closeOnPressEscape, fullscreen, destroyOnClose。内容超出视口时 body 自动滚动,header/footer 固定。**注意:body 区域有 `overflow-y-auto`,首尾位置的 input/select 等表单控件的 focus-ring 会被裁切,需在内容区域添加 `p-1` 或 `py-1` padding 规避** |
120
- | EDrawer | 抽屉 | v-model:open, title, description, direction(top/right/bottom/left), showClose |
121
- | ESheet | 侧边面板 | v-model:open, title, description, side(top/right/bottom/left), showClose |
122
- | EAlertDialog | 确认对话框 | v-model:open, title, description, confirmText, cancelText |
123
- | ETooltip | 提示气泡 | content, side, sideOffset, delayDuration, disabled |
124
- | EPopover | 弹出卡片 | v-model:open, side, sideOffset, align |
125
- | EHoverCard | 悬停卡片 | openDelay, closeDelay |
126
- | EToast | 轻提示 | position, expand, richColors(配合 `toast()` 函数使用) |
127
- | EContextMenu | 右键菜单 | items(ContextMenuItem[]) |
117
+ ---
128
118
 
129
- ### 导航与布局
119
+ ## 重要约束与已知陷阱
130
120
 
131
- | 组件 | 用途 | 关键 Props |
132
- |------|------|-----------|
133
- | ETabs | 标签页 | v-model, items(TabItem[]), closable, addable, tabPosition(top/bottom/left/right) |
134
- | EMenu | 侧边菜单 | v-model, items(MenuItem[]), collapsed, router, uniqueOpened, defaultOpeneds |
135
- | EDropdown | 下拉菜单 | items(DropdownMenuItem[]), side, align, sideOffset, trigger(click/hover), splitButton, buttonText, buttonVariant |
136
- | EAccordion | 手风琴 | v-model, items(AccordionItemOption[]), multiple, collapsible |
137
- | ECollapsible | 折叠面板 | v-model(boolean), disabled |
138
- | EStepper | 步骤条 | v-model, items(StepperItem[]), direction(horizontal/vertical) |
139
- | ECarousel | 轮播 | loop, direction, showArrows, showDots, autoplay, interval。子组件 ECarouselItem |
140
- | EScrollArea | 自定义滚动区 | type(auto/always/scroll/hover) |
141
- | EInfiniteScroll | 无限滚动 | loading, disabled, distance |
142
-
143
- ### 复合组件
144
-
145
- 以下组件由多个子组件组合使用,通过 `provide/inject` 共享状态:
146
-
147
- | 组件 | 子组件 | 用途 |
148
- |------|--------|------|
149
- | ECommand | ECommandInput, ECommandList, ECommandEmpty, ECommandGroup, ECommandItem, ECommandSeparator, ECommandShortcut | 命令面板(配合 useCommand) |
150
- | ENavigationMenu | ENavigationMenuList, ENavigationMenuItem, ENavigationMenuTrigger, ENavigationMenuContent, ENavigationMenuLink, ENavigationMenuViewport | 导航菜单 |
151
- | EMenubar | EMenubarMenu, EMenubarTrigger, EMenubarContent, EMenubarItem, EMenubarSeparator, EMenubarCheckboxItem, EMenubarRadioGroup, EMenubarRadioItem, EMenubarSub, EMenubarSubTrigger, EMenubarSubContent | 菜单栏 |
152
- | EResizable | EResizablePanelGroup(direction), EResizablePanel(defaultSize, minSize, maxSize), EResizableHandle(withHandle) | 可调整大小面板 |
153
-
154
- ### 其他
155
-
156
- | 组件 | 用途 | 关键 Props |
157
- |------|------|-----------|
158
- | EConfigProvider | **必须**包裹 App 根组件,提供国际化/尺寸/层级全局配置 | size, zIndex, locale(Record, 含 name 字段为 BCP 47 语言标签,默认 zh-CN) |
159
- | EToggle | 切换按钮 | v-model, variant(default/outline), size, disabled |
160
- | EToggleGroup | 切换按钮组 | v-model, type(single/multiple), variant, size, disabled |
161
- | EButtonGroup | 按钮组 | orientation(horizontal/vertical) |
162
- | EItem | 列表项 | variant(default/outline/muted), size(default/sm), as |
163
- | EAspectRatio | 宽高比容器 | ratio |
164
- | EAffix | 固钉 | offset, position(top/bottom) |
165
- | EWatermark | 水印 | content, fontSize, rotate, gap, opacity |
166
- | EChartContainer | 图表容器 | config(ChartConfig), id |
121
+ 源码读不出来的"踩坑经验",每次写 EUI 代码都遵守:
167
122
 
168
- ### 业务组件
123
+ ### 表单
124
+ - **禁止用原生 `<form>` 标签**,所有表单必须用 `<EForm>`。EForm 内置 vee-validate 校验、provide/inject 上下文、统一 label 布局和 reset/validate API,原生 `<form>` 无法集成
125
+ - `ESelect` 的 `option.value` **不能为空字符串**,reka-ui 不支持
126
+ - 表单校验优先用 zod schema 传给 `EForm` 的 `rules` prop
127
+
128
+ ### 弹层
129
+ - `EDialog` body 区域有 `overflow-y-auto`,**首尾位置的 input/select 等表单控件的 focus-ring 会被裁切**。规避:在内容区域加 `p-1` 或 `py-1` padding
130
+ - 弹层组件统一用 `v-model:open` 控制显隐,不要用 `:visible` / `@update:visible`
131
+
132
+ ### reka-ui 绑定约定
133
+ - 封装 reka-ui 组件时统一用 `v-model`(`modelValue` / `update:modelValue`),**不是** `:checked` / `@update:checked`
134
+ - 自己写组件包 reka-ui 原语时必须用 `v-model` 或 writable computed 绑定
135
+
136
+ ### 全局配置
137
+ - `EConfigProvider` 必须包裹 App 根组件,提供国际化(locale)/ 默认尺寸 / zIndex
138
+ - `locale.name` 字段必须是 BCP 47 语言标签(如 `zh-CN`、`en-US`),默认 `zh-CN`
169
139
 
170
- | 组件 | 用途 | 关键 Props |
171
- |------|------|-----------|
172
- | EDataPage | 数据列表页 | columns(TableColumn[]), fetchFn(async), searchable, pageSize。内置表格 + 分页 + 搜索 |
173
- | EFormDialog | 表单弹窗 | v-model:open, title, size, loading, confirmText, cancelText |
174
- | EConfirmDialog | 确认弹窗 | v-model:open, title, message, type(info/warning/error), confirmText, cancelText |
175
- | EAdminLayout | 后台管理布局 | logo, title, menuItems(MenuItem[]), v-model:activeKey, v-model:collapsed, headerHeight, sidebarWidth |
176
- | EAIChat | AI 对话 | messages(ChatMessage[]), loading, placeholder |
177
- | ETimetableGrid | 课程表/时间表 | data(TimetableItem[]), startHour, endHour, days |
140
+ ### 样式
141
+ - 使用 `cn()` 合并 Tailwind 类名(解决冲突):`cn('px-2 py-1', isActive && 'bg-primary text-white', className)`
142
+ - 主题切换通过 `useTheme()` 的 `setColorTheme()` / `toggleDark()`,**不要**手动操作 `<html class="dark">`
178
143
 
179
144
  ---
180
145
 
181
- ## Composables
146
+ ## Composables 速查
182
147
 
183
- | Composable | 用途 | 返回值 |
184
- |------------|------|--------|
185
- | useMessage() | 全局消息提示 | { success, warning, error, info } — 每个接收 string 或 MessageOptions |
186
- | useNotification() | 通知 | { success, warning, error, info } — 接收 NotificationOptions(title, message, position, duration, onClick, closable) |
187
- | useMessageBox() | 对话确认 | { alert, confirm, prompt } — 返回 Promise<'confirm' \| 'cancel'> |
188
- | useToast() | Toast 通知(与 EToast 组件配合使用) | { toast, dismiss, toasts } — toast 接收 ToastOptions(title, description, variant) |
189
- | useTheme() | 主题管理 | { isDark, theme, setTheme, toggleDark, colorTheme, setColorTheme } |
190
- | useConfigProvider() | 读取全局配置 | { size, zIndex, locale } |
191
- | useFormField() | 表单字段上下文 | { id, name, formItemId, valid, isDirty, isTouched, error }(需在 FormField 内使用) |
192
- | useSecureValue() | 敏感输入安全绑定 | { isComposing, recordCursor, setCursor, setNativeValue, onCompositionStart, onCompositionEnd } — 通过 DOM property 赋值避免密码泄露到 HTML attribute |
148
+ | Composable | 用途 |
149
+ |------------|------|
150
+ | `useMessage()` | 全局消息提示(success / warning / error / info) |
151
+ | `useNotification()` | 通知(含 title / message / position / duration) |
152
+ | `useMessageBox()` | 对话确认(alert / confirm / prompt),返回 Promise |
153
+ | `useTheme()` | 主题管理(isDark / setTheme / setColorTheme / toggleDark) |
154
+ | `useConfigProvider()` | 读取全局配置(size / zIndex / locale) |
155
+ | `useFormField()` | 表单字段上下文(id / name / valid / error),需在 FormField 内使用 |
156
+ | `useSecureValue()` | 敏感输入安全绑定(DOM property 赋值,避免密码泄露到 HTML attribute) |
157
+
158
+ 精确签名读 `<project-root>/node_modules/@dwydev/eui/dist/composables/{name}.d.ts`。
159
+
160
+ ---
193
161
 
194
162
  ## 主题系统
195
163
 
196
- - **Design Tokens**: CSS 自定义属性,定义在 `tokens.css`,前缀 `--`(如 `--primary`, `--background`)
197
- - **暗色模式**: `dark.css`,通过 `<html class="dark">` 切换
198
- - **色彩主题**: 7 种(neutral/blue/green/rose/orange/violet/slate),通过 `useTheme().setColorTheme()` 切换
199
- - **样式工具**: 使用 `cn()` 合并 Tailwind 类名,自动解决冲突
164
+ - **Design Tokens**:CSS 自定义属性,定义在 `tokens.css`,前缀 `--`(如 `--primary`、`--background`)
165
+ - **暗色模式**:`dark.css`,通过 `<html class="dark">` 切换(用 `useTheme().toggleDark()`,不手写)
166
+ - **色彩主题**:7 种(neutral / blue / green / rose / orange / violet / slate),通过 `useTheme().setColorTheme()` 切换
167
+ - 样式入口:`import '@dwydev/eui/theme'`
200
168
 
201
- ```ts
202
- import { cn } from '@dwydev/eui'
203
- cn('px-2 py-1', isActive && 'bg-primary text-white', className)
204
- ```
169
+ ---
205
170
 
206
- ## 通用类型
171
+ ## 通用类型速查
172
+
173
+ 精确定义读 `<project-root>/node_modules/@dwydev/eui/dist/types.d.ts`。常用:
207
174
 
208
175
  ```ts
209
176
  type Size = 'sm' | 'default' | 'lg'
210
177
 
211
178
  interface Option {
212
179
  label: string
213
- value: string | number
180
+ value: string | number // ⚠️ 不能为空字符串
214
181
  disabled?: boolean
215
182
  }
216
183
 
217
- interface GroupedOption {
218
- label: string
219
- options: Option[]
220
- }
221
-
222
184
  interface MenuItem {
223
185
  key: string
224
186
  label: string
225
187
  icon?: string
226
- /** Route path for router mode (falls back to key if not provided) */
227
- path?: string
188
+ path?: string // router 模式下的路由路径
228
189
  children?: MenuItem[]
229
190
  disabled?: boolean
230
191
  }
@@ -239,13 +200,134 @@ interface TableColumn<T = any> {
239
200
  align?: 'left' | 'center' | 'right'
240
201
  render?: (row: T, index: number) => any
241
202
  }
203
+ ```
242
204
 
243
- type DatePickerType = 'date' | 'daterange' | 'month' | 'year'
205
+ ---
244
206
 
245
- interface DatePickerShortcut {
246
- text: string
247
- value: Date | Date[] | (() => Date | Date[])
248
- }
207
+ ## 组件目录索引
208
+
209
+ 按用途分类的导航表,**只提供组件名 + 一句话用途**,精确 props/emits 一律按 [查 API 标准动作](#查-api-标准动作核心每次用组件前都做) 读 `types.d.ts`。
210
+
211
+ ### 基础展示
212
+
213
+ | 组件 | 用途 |
214
+ |------|------|
215
+ | `EButton` | 按钮(含 loading 状态) |
216
+ | `EButtonGroup` | 按钮组 |
217
+ | `EBadge` | 标签徽章 |
218
+ | `EAlert` | 警告提示 |
219
+ | `ECard` | 卡片容器 |
220
+ | `ELabel` | 标签文本 |
221
+ | `ESeparator` | 分隔线 |
222
+ | `ETypography` | 排版文本 |
223
+ | `EKbd` | 键盘按键展示 |
224
+ | `ESpinner` | 加载动画 |
225
+ | `EProgress` | 进度条 |
226
+ | `ESkeleton` | 骨架屏 |
227
+ | `EEmpty` | 空状态 |
228
+ | `EAvatar` | 头像 |
229
+ | `EImage` | 图片(含懒加载/预览) |
230
+ | `EAspectRatio` | 宽高比容器 |
231
+ | `EAffix` | 固钉 |
232
+ | `EWatermark` | 水印 |
233
+
234
+ ### 表单输入
235
+
236
+ | 组件 | 用途 |
237
+ |------|------|
238
+ | `EForm` / `EFormItem` | 表单容器与表单项(必用,禁用原生 form) |
239
+ | `EField` | 字段布局(垂直/水平/响应式) |
240
+ | `EInput` | 输入框(含 password / clearable / 字数统计) |
241
+ | `EInputGroup` | 输入组(含 prefix/suffix addon) |
242
+ | `ETextarea` | 多行输入(含自适应高度) |
243
+ | `ENumberField` | 数字输入 |
244
+ | `ESelect` | 下拉选择(option.value ≠ '') |
245
+ | `ENativeSelect` | 原生 select |
246
+ | `ECombobox` | 组合框(可输入下拉) |
247
+ | `EAutocomplete` | 自动补全 |
248
+ | `ECheckbox` | 复选框/复选组 |
249
+ | `ERadio` | 单选组 |
250
+ | `ESwitch` | 开关 |
251
+ | `ETagsInput` | 标签输入 |
252
+ | `EDatePicker` | 日期/范围/月/年选择 |
253
+ | `ETimePicker` | 时间选择 |
254
+ | `EColorPicker` | 颜色选择 |
255
+ | `ERate` | 评分 |
256
+ | `ESlider` | 滑块 |
257
+ | `ECascader` | 级联选择 |
258
+ | `ETreeSelect` | 树选择 |
259
+ | `EMention` | @提及输入 |
260
+ | `EInputOTP` | OTP 验证码 |
261
+ | `EPinInput` | PIN 输入 |
262
+ | `EUpload` | 文件上传(含拖拽/图片墙) |
263
+ | `ETransfer` | 穿梭框 |
249
264
 
250
- type TabPosition = 'top' | 'bottom' | 'left' | 'right'
251
- ```
265
+ ### 数据展示
266
+
267
+ | 组件 | 用途 |
268
+ |------|------|
269
+ | `ETable` | 表格(含排序/选择/展开/虚拟滚动/列固定) |
270
+ | `EVirtualTable` | 虚拟滚动表格(大数据专用) |
271
+ | `EDescriptions` | 描述列表 |
272
+ | `ETimeline` | 时间线 |
273
+ | `EStatistic` | 统计数值 |
274
+ | `ETree` | 树形控件 |
275
+ | `ECalendar` | 日历 |
276
+ | `ERangeCalendar` | 日期范围日历 |
277
+ | `EPagination` | 分页 |
278
+ | `EBreadcrumb` | 面包屑 |
279
+ | `EChartContainer` | 图表容器 |
280
+
281
+ ### 弹层与反馈
282
+
283
+ | 组件 | 用途 |
284
+ |------|------|
285
+ | `EDialog` | 对话框(v-model:open,body 区域 padding 见踩坑提示) |
286
+ | `EDrawer` | 抽屉 |
287
+ | `ESheet` | 侧边面板 |
288
+ | `EAlertDialog` | 确认对话框 |
289
+ | `ETooltip` | 提示气泡 |
290
+ | `EPopover` | 弹出卡片 |
291
+ | `EHoverCard` | 悬停卡片 |
292
+ | `EToast` | 轻提示(配合 useToast / `toast()`) |
293
+ | `EContextMenu` | 右键菜单 |
294
+
295
+ ### 导航与布局
296
+
297
+ | 组件 | 用途 |
298
+ |------|------|
299
+ | `ETabs` | 标签页 |
300
+ | `EMenu` | 侧边菜单 |
301
+ | `EDropdown` | 下拉菜单 |
302
+ | `EAccordion` | 手风琴 |
303
+ | `ECollapsible` | 折叠面板 |
304
+ | `EStepper` | 步骤条 |
305
+ | `ECarousel` | 轮播 |
306
+ | `EScrollArea` | 自定义滚动区 |
307
+ | `EInfiniteScroll` | 无限滚动 |
308
+ | `EToggle` / `EToggleGroup` | 切换按钮 |
309
+ | `EItem` | 列表项 |
310
+ | `EResizablePanelGroup` 等 | 可调整大小面板(复合组件) |
311
+
312
+ ### 复合组件(子组件需配合使用)
313
+
314
+ | 主组件 | 用途 |
315
+ |--------|------|
316
+ | `ECommand` | 命令面板(含 ECommandInput / List / Empty / Group / Item / Separator / Shortcut) |
317
+ | `ENavigationMenu` | 导航菜单(含 List / Item / Trigger / Content / Link / Viewport) |
318
+ | `EMenubar` | 菜单栏(含 Menu / Trigger / Content / Item / Separator / Checkbox / Radio / Sub) |
319
+ | `EResizable` | 可调整大小(含 PanelGroup / Panel / Handle) |
320
+
321
+ 复合组件的全部子组件名查 `component-manifest.json` 的 `directories[{kebab}].components`。
322
+
323
+ ### 业务组件
324
+
325
+ | 组件 | 用途 |
326
+ |------|------|
327
+ | `EDataPage` | 数据列表页(内置表格 + 分页 + 搜索) |
328
+ | `EFormDialog` | 表单弹窗 |
329
+ | `EConfirmDialog` | 确认弹窗(类型: info / warning / error) |
330
+ | `EAdminLayout` | 后台管理布局(顶部 + 侧边栏 + 主内容) |
331
+ | `EAIChat` | AI 对话 |
332
+ | `ETimetableGrid` | 课程表/时间表 |
333
+ | `EConfigProvider` | 全局配置(必须包裹 App 根) |