@agile-team/wl-skills-ui 1.9.11 → 1.9.13

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.
@@ -0,0 +1,63 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { issue, lineOf } from "./_shared.mjs";
3
+
4
+ const registry = JSON.parse(
5
+ readFileSync(
6
+ new URL("../../standards/component-structures.json", import.meta.url),
7
+ "utf8",
8
+ ),
9
+ );
10
+ const knownRootClasses = new Set(
11
+ registry.contracts.flatMap((contract) => contract.knownRootClasses || []),
12
+ );
13
+
14
+ const CLASS_ATTRIBUTE = /class\s*=\s*["']([^"']+)["']/g;
15
+ const COMPOSITE_NAME = /(?:multi|multiple|picker|tags?|input-number|split)/i;
16
+
17
+ export function findUnknownCompositeRoots(template) {
18
+ const findings = [];
19
+ let match;
20
+ while ((match = CLASS_ATTRIBUTE.exec(template)) !== null) {
21
+ const classValue = match[1];
22
+ const classes = classValue.split(/\s+/).filter(Boolean);
23
+ if (classes.some((name) => knownRootClasses.has(name))) continue;
24
+
25
+ const isHybridElementWrapper =
26
+ classes.includes("el-input") && classes.includes("el-input__wrapper");
27
+ const looksComposite = COMPOSITE_NAME.test(classValue);
28
+ const nearby = template.slice(match.index, match.index + 1600);
29
+ const containsInputStructure =
30
+ /<el-(?:input|select|autocomplete|cascader)\b|el-(?:input|select)__wrapper/.test(
31
+ nearby,
32
+ );
33
+
34
+ if (isHybridElementWrapper || (looksComposite && containsInputStructure)) {
35
+ findings.push({ index: match.index, classValue });
36
+ }
37
+ }
38
+ CLASS_ATTRIBUTE.lastIndex = 0;
39
+ return findings;
40
+ }
41
+
42
+ export const componentStructureRules = [
43
+ {
44
+ id: "R040",
45
+ category: "composite",
46
+ severity: "review",
47
+ name: "未知复合控件结构必须先登记边框与高度契约",
48
+ check(template, file, lineOffset) {
49
+ return findUnknownCompositeRoots(template).map((finding) =>
50
+ issue(
51
+ file,
52
+ lineOf(template, finding.index, lineOffset),
53
+ "R040",
54
+ "composite",
55
+ "review",
56
+ `发现未登记的疑似复合控件结构:class="${finding.classValue}"`,
57
+ "先核对真实 DOM,明确 root/边框所有者/内部无描边层/高度策略/Teleport 出口,再登记到 standards/component-structures.json;禁止直接扩大普通 Element 选择器。",
58
+ { layer: "L2", vendor: "common-core" },
59
+ ),
60
+ );
61
+ },
62
+ },
63
+ ];
@@ -17,6 +17,7 @@ import { colorRules } from "./color.mjs";
17
17
  import { dialogRules } from "./dialog.mjs";
18
18
  import { tagRules } from "./tag.mjs";
19
19
  import { componentFamilyRules } from "./componentFamily.mjs";
20
+ import { componentStructureRules } from "./componentStructure.mjs";
20
21
  import { semanticRules } from "./semantic.mjs";
21
22
 
22
23
  export const BUILT_IN_RULES = [
@@ -27,6 +28,7 @@ export const BUILT_IN_RULES = [
27
28
  ...dialogRules,
28
29
  ...tagRules,
29
30
  ...componentFamilyRules,
31
+ ...componentStructureRules,
30
32
  ...semanticRules,
31
33
  ];
32
34
 
@@ -67,6 +67,9 @@ el-date-picker 默认宽度不会自动撑满 el-form-item,必须显式设置
67
67
  平台默认阴影。
68
68
  - 数字输入框必须同时检查社区版“wrapper 子节点”和 jh-ui“wrapper 与
69
69
  input-number 同节点”两种 DOM,并确保只存在一层可见边框。
70
+ - 带 prepend/append 的 input-group 必须由组合根绘制唯一外轮廓;输入主体、附加段
71
+ 统一 26px,左右图标统一 14px。纯图标附加段使用 32px,文字/单位/按钮保持内容宽度。
72
+ 不允许业务页分别给 `.el-input__inner` 与 `.el-input-group__append` 写不同高度。
70
73
  - 登录页和显式定制页继续使用自身样式,不套用上述高权重规则。
71
74
 
72
75
  ---
@@ -34,6 +34,7 @@ applyTo: "**/*.vue"
34
34
  - EP 2.2.x `.el-input__inner` 26px 高度、圆角 / focus / error 三态
35
35
  - jh-picker / reference-picker 的 `.com-picker` / `.com-reference-picker` 输入高度兜底
36
36
  - common-core 多标签/人员选择器的 `.com-input-multi-tag-wrap` 使用 26px 最小高度并允许标签换行自然增高;只由外层绘制统一状态边框,内部编辑 input 不重复描边
37
+ - common-core 复合结构统一登记在 `standards/component-structures.json`;R040 遇到未登记的疑似 picker/multiple/tag 混合 wrapper 时只提示人工核对,不允许直接放大通用 Element 选择器
37
38
  - jh-select / jh-date-picker 的 `.el-select.is-focus` / `.el-input.is-focus` 兼容
38
39
  - 必填星号在 inline-flex label 下显式声明颜色
39
40
 
@@ -48,10 +49,12 @@ applyTo: "**/*.vue"
48
49
 
49
50
  - ❌ 自行给 `.jh-tree` 写颜色覆盖(应用全局 `vendors/_jh-tree.scss`)
50
51
  - ❌ jh-drag-col 内自定义 padding 破坏拖拽条对齐
51
- - ❌ jh-drag-row 上下分栏缺 `.drager_row { height:100% }` 高度链(拖拽失效),或页面自行重画 `.slider_row`;手柄必须统一使用 `_jh-drag-row.scss` 的细分隔线 + 三点胶囊
52
+ - ❌ jh-drag-row 上下分栏缺可收缩高度链,拖动后仅靠 pane 的 `overflow:hidden` 裁切 AG Grid;必须接入 `runtime/auto`,由 ResizeObserver 通知表格内部重布局,禁止给外层随意加滚动条
53
+ - ❌ 页面自行重画 `.slider_row`;手柄必须统一使用 `_jh-drag-row.scss` 的细分隔线 + 三点胶囊
52
54
  - ❌ jh-pagination 未对齐到右侧(同 R011)
53
55
  - ❌ jh-form 内不用 `size="small"` 控件(同 R006)
54
56
  - ❌ 发现新的复杂 `<jh-*>` 组件后只在页面局部写补丁,而不沉淀到 L2 Project Vendors
57
+ - ❌ 新复合结构未登记边框所有者、高度策略、内部无描边层与 Teleport 出口就直接写全局覆盖(R040)
55
58
 
56
59
  ## Repair
57
60
 
@@ -63,6 +66,7 @@ applyTo: "**/*.vue"
63
66
  ### B 类
64
67
 
65
68
  - 直接全局覆盖 `.jh-*` → 改为引入 `wl-skills-ui/styles` 由 vendors 层处理
69
+ - `jh-drag-row + AG Grid` → Skin 项目除样式外在启动入口引入一次 `@agile-team/wl-skills-ui/runtime/auto`;Native 项目使用 `installCommonPreset()`,详见 `docs/split-grid-resize.md`
66
70
  - 新的复杂 `<jh-*>` 组件 → 先判断是否只是 Element Plus 薄封装;若不是,应新增 `styles/vendors/_jh-xxx.scss` 和对应 Skill/检测规则
67
71
 
68
72
  ## 全局样式来源
@@ -0,0 +1,313 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "description": "复合/组合控件结构契约单一事实源。登记边框所有者、高度策略、内部无描边层和 Teleport 出口,防止普通 Element 选择器误识别。",
4
+ "heightPolicies": [
5
+ "fixed-control-height",
6
+ "auto-with-control-min-height",
7
+ "content-driven"
8
+ ],
9
+ "contracts": [
10
+ {
11
+ "id": "common-core.multi-tag-input",
12
+ "vendor": "common-core",
13
+ "family": "form-composite",
14
+ "source": "lowcode-engine/packages/common/common-lowcode/components/src/schema-component/base-input-group/input/com/multi-tag-input.vue",
15
+ "fixture": "scanner/__tests__/component-fixtures/common-core-multi-tag-input.html",
16
+ "rootSelector": ".com-input-multi-tag-wrap.el-input.el-input__wrapper",
17
+ "ownerSelector": ".com-input-multi-tag-wrap.el-input__wrapper",
18
+ "innerBorderlessSelectors": [
19
+ ".com-input-multi-tag-wrap .el-input__wrapper"
20
+ ],
21
+ "knownRootClasses": [
22
+ "com-input-multi-tag-wrap"
23
+ ],
24
+ "heightPolicy": "auto-with-control-min-height",
25
+ "states": [
26
+ "default",
27
+ "hover",
28
+ "focus",
29
+ "error",
30
+ "disabled"
31
+ ],
32
+ "assertions": [
33
+ {
34
+ "target": "root",
35
+ "selector": ".el-input__wrapper:not(.com-input-multi-tag-wrap)",
36
+ "matches": false
37
+ },
38
+ {
39
+ "target": "inner",
40
+ "selector": ".com-input-multi-tag-wrap .el-input__wrapper",
41
+ "matches": true
42
+ }
43
+ ],
44
+ "risk": "外壳同时携带 el-input 与 el-input__wrapper,内部又包含真实 input wrapper;误套固定高度会裁切标签,内外同时描边会出现双边框。"
45
+ },
46
+ {
47
+ "id": "common-core.user-picker-multiple",
48
+ "vendor": "common-core",
49
+ "family": "picker-composite",
50
+ "source": "lowcode-engine/packages/common/common-lowcode/components/src/schema-component/base-input-group/user-picker/com/multiple-picker.vue",
51
+ "fixture": "scanner/__tests__/component-fixtures/common-core-user-picker-multiple.html",
52
+ "rootSelector": ".com-userPicker.picker-wrap",
53
+ "ownerSelector": ".com-userPicker .com-input-multi-tag-wrap.el-input__wrapper",
54
+ "innerBorderlessSelectors": [
55
+ ".com-userPicker .com-input-multi-tag-wrap .el-input__wrapper"
56
+ ],
57
+ "portalSelectors": [
58
+ ".user-picker-popper",
59
+ ".com-userPicker-dialog"
60
+ ],
61
+ "knownRootClasses": [
62
+ "com-userPicker"
63
+ ],
64
+ "heightPolicy": "auto-with-control-min-height",
65
+ "states": [
66
+ "default",
67
+ "hover",
68
+ "focus",
69
+ "error",
70
+ "disabled",
71
+ "open"
72
+ ],
73
+ "risk": "多标签外壳、Tooltip 和 append-to-body Dialog 同时存在,页面内样式与 Teleport 浮层必须分别验证。"
74
+ },
75
+ {
76
+ "id": "common-core.dept-picker-multiple",
77
+ "vendor": "common-core",
78
+ "family": "picker-composite",
79
+ "source": "lowcode-engine/packages/common/common-lowcode/components/src/schema-component/base-input-group/dept-picker/com/multiple-picker.vue",
80
+ "fixture": "scanner/__tests__/component-fixtures/common-core-dept-picker-multiple.html",
81
+ "rootSelector": ".com-deptPicker.picker-wrap",
82
+ "ownerSelector": ".com-deptPicker .el-input__wrapper",
83
+ "innerBorderlessSelectors": [],
84
+ "portalSelectors": [
85
+ ".com-deptPicker-dialog"
86
+ ],
87
+ "knownRootClasses": [
88
+ "com-deptPicker"
89
+ ],
90
+ "heightPolicy": "fixed-control-height",
91
+ "states": [
92
+ "default",
93
+ "hover",
94
+ "focus",
95
+ "error",
96
+ "disabled",
97
+ "open"
98
+ ],
99
+ "risk": "输入触发器与 append-to-body Dialog 分离,作用域或弹层规则调整时容易只覆盖一侧。"
100
+ },
101
+ {
102
+ "id": "common-core.tree-picker",
103
+ "vendor": "common-core",
104
+ "family": "picker-composite",
105
+ "source": "lowcode-engine/packages/common/common-lowcode/components/src/schema-component/base-input-group/tree-picker/com-pc/tree-picker.vue",
106
+ "fixture": "scanner/__tests__/component-fixtures/common-core-tree-picker.html",
107
+ "rootSelector": ".com-treePicker.picker-wrap",
108
+ "ownerSelector": ".com-treePicker-input .el-input__wrapper",
109
+ "innerBorderlessSelectors": [],
110
+ "portalSelectors": [
111
+ ".com-treePicker-dialog"
112
+ ],
113
+ "knownRootClasses": [
114
+ "com-treePicker"
115
+ ],
116
+ "heightPolicy": "fixed-control-height",
117
+ "states": [
118
+ "default",
119
+ "hover",
120
+ "focus",
121
+ "error",
122
+ "disabled",
123
+ "open"
124
+ ],
125
+ "risk": "外部触发输入、树弹窗和弹窗内搜索输入属于不同层级,通用输入规则不能把三者视为一个边框所有者。"
126
+ },
127
+ {
128
+ "id": "common-core.select-multiple",
129
+ "vendor": "common-core",
130
+ "family": "select-composite",
131
+ "source": "lowcode-engine/packages/common/common-lowcode/components/src/schema-component/base-input-group/select/com/select.vue",
132
+ "fixture": "scanner/__tests__/component-fixtures/common-core-select-multiple.html",
133
+ "rootSelector": ".el-select.com-select-multiple",
134
+ "ownerSelector": ".el-select.com-select-multiple .el-select__wrapper",
135
+ "innerBorderlessSelectors": [
136
+ ".el-select.com-select-multiple .el-select__input"
137
+ ],
138
+ "portalSelectors": [
139
+ ".el-select__popper"
140
+ ],
141
+ "knownRootClasses": [
142
+ "com-select-multiple"
143
+ ],
144
+ "heightPolicy": "auto-with-control-min-height",
145
+ "states": [
146
+ "default",
147
+ "hover",
148
+ "focus",
149
+ "error",
150
+ "disabled",
151
+ "open"
152
+ ],
153
+ "risk": "Tag、过滤输入和 Teleport 下拉层共存;必须保留多选自然增高并避免内部 editor 重复描边。"
154
+ },
155
+ {
156
+ "id": "common-core.input-number-mixed-wrapper",
157
+ "vendor": "common-core",
158
+ "family": "number-composite",
159
+ "source": "lowcode-engine/packages/common/common-lowcode/components/src/schema-component/base-input-group/input-number/com/input-number.vue",
160
+ "fixture": "scanner/__tests__/component-fixtures/common-core-input-number-mixed.html",
161
+ "rootSelector": ".el-input-number.el-input__wrapper",
162
+ "ownerSelector": ".el-input-number.el-input__wrapper",
163
+ "innerBorderlessSelectors": [
164
+ ".el-input-number.el-input__wrapper > .el-input > .el-input__wrapper"
165
+ ],
166
+ "knownRootClasses": [
167
+ "el-input-number"
168
+ ],
169
+ "heightPolicy": "fixed-control-height",
170
+ "states": [
171
+ "default",
172
+ "hover",
173
+ "focus",
174
+ "error",
175
+ "disabled"
176
+ ],
177
+ "assertions": [
178
+ {
179
+ "target": "root",
180
+ "selector": ".el-input-number.el-input__wrapper",
181
+ "matches": true
182
+ },
183
+ {
184
+ "target": "inner",
185
+ "selector": ".el-input-number.el-input__wrapper > .el-input > .el-input__wrapper",
186
+ "matches": true
187
+ }
188
+ ],
189
+ "risk": "根节点本身是 wrapper,内部仍含 Element input wrapper;只能由根节点绘制唯一状态边框。"
190
+ },
191
+ {
192
+ "id": "common-core.base-toolbar-split-button",
193
+ "vendor": "common-core",
194
+ "family": "action-composite",
195
+ "source": "common-core BaseToolbar split-button rendered DOM",
196
+ "fixture": "scanner/__tests__/component-fixtures/common-core-base-toolbar-split.html",
197
+ "rootSelector": ".base-toolbar-box .action-button-wrap > .el-dropdown > .el-button-group",
198
+ "ownerSelector": ".base-toolbar-box .action-button-wrap > .el-dropdown > .el-button-group",
199
+ "innerBorderlessSelectors": [
200
+ ".base-toolbar-box .action-button-wrap > .el-dropdown > .el-button-group > .el-dropdown__caret-button"
201
+ ],
202
+ "portalSelectors": [
203
+ ".el-dropdown-menu.action-dropdown-menu"
204
+ ],
205
+ "knownRootClasses": [
206
+ "action-button-wrap"
207
+ ],
208
+ "heightPolicy": "content-driven",
209
+ "states": [
210
+ "default",
211
+ "hover",
212
+ "focus",
213
+ "active",
214
+ "disabled",
215
+ "open"
216
+ ],
217
+ "risk": "主动作和箭头是两个交互区但必须共享一个视觉外轮廓;下拉菜单中的业务按钮需扁平化且不能污染普通菜单。"
218
+ },
219
+ {
220
+ "id": "element-plus.input-group-affixes",
221
+ "vendor": "element-plus",
222
+ "family": "form-composite",
223
+ "source": "Element Plus Input prepend/append slot DOM;common-core jh-input 沿用该结构",
224
+ "fixture": "scanner/__tests__/component-fixtures/element-input-group-affixes.html",
225
+ "rootSelector": ".el-input.el-input-group",
226
+ "ownerSelector": ".el-input.el-input-group",
227
+ "innerBorderlessSelectors": [
228
+ ".el-input.el-input-group > .el-input__wrapper"
229
+ ],
230
+ "knownRootClasses": [
231
+ "el-input-group"
232
+ ],
233
+ "heightPolicy": "fixed-control-height",
234
+ "states": [
235
+ "default",
236
+ "hover",
237
+ "focus",
238
+ "error",
239
+ "disabled"
240
+ ],
241
+ "assertions": [
242
+ {
243
+ "target": "root",
244
+ "selector": ".el-input.el-input-group",
245
+ "matches": true
246
+ },
247
+ {
248
+ "target": "inner",
249
+ "selector": ".el-input.el-input-group > .el-input__wrapper",
250
+ "matches": true
251
+ }
252
+ ],
253
+ "risk": "输入主体、prepend/append 和内部图标原本各自携带高度、圆角与描边;必须由组合根统一外轮廓,仅保留内部接缝,避免附加段独立成块。"
254
+ },
255
+ {
256
+ "id": "common-core.drag-row-ag-grid",
257
+ "vendor": "common-core",
258
+ "family": "layout-composite",
259
+ "source": "lowcode-engine/packages/common/common-lowcode/components-core/src/components/drag-row/drag-row.vue + BaseTable renderType=agGrid DOM",
260
+ "fixture": "scanner/__tests__/component-fixtures/common-core-drag-row-ag-grid.html",
261
+ "rootSelector": ".drager_row",
262
+ "ownerSelector": ".drager_row .ag-grid-table",
263
+ "innerBorderlessSelectors": [],
264
+ "knownRootClasses": [
265
+ "drager_row"
266
+ ],
267
+ "heightPolicy": "content-driven",
268
+ "states": [
269
+ "initial",
270
+ "dragging",
271
+ "drag-end",
272
+ "container-resize"
273
+ ],
274
+ "risk": "分屏 pane 使用 overflow:hidden,拖动后若 AG Grid 宿主没有沿 flex 高度链收缩,只会裁掉旧尺寸内容而不会生成内部纵向滚动条。"
275
+ },
276
+ {
277
+ "id": "element-plus.input-group-affixes-legacy",
278
+ "vendor": "element-plus",
279
+ "family": "form-composite",
280
+ "source": "jh-ui 3.1.0 配套 Element Plus 2.2.x Input prepend/append 直挂 DOM",
281
+ "fixture": "scanner/__tests__/component-fixtures/element-input-group-affixes-legacy.html",
282
+ "rootSelector": ".el-input.el-input-group",
283
+ "ownerSelector": ".el-input.el-input-group",
284
+ "innerBorderlessSelectors": [
285
+ ".el-input.el-input-group > .el-input__inner"
286
+ ],
287
+ "knownRootClasses": [
288
+ "el-input-group"
289
+ ],
290
+ "heightPolicy": "fixed-control-height",
291
+ "states": [
292
+ "default",
293
+ "hover",
294
+ "focus",
295
+ "error",
296
+ "disabled"
297
+ ],
298
+ "assertions": [
299
+ {
300
+ "target": "root",
301
+ "selector": ".el-input.el-input-group",
302
+ "matches": true
303
+ },
304
+ {
305
+ "target": "inner",
306
+ "selector": ".el-input.el-input-group > .el-input__inner",
307
+ "matches": true
308
+ }
309
+ ],
310
+ "risk": "旧 DOM 没有 el-input__wrapper;若只清理新版 wrapper,直挂 input 会保留第二层边框并与 append 高度错位。"
311
+ }
312
+ ]
313
+ }
@@ -44,6 +44,10 @@
44
44
  "layout": {
45
45
  "label": "页面骨架 / 操作组合",
46
46
  "standardsDoc": "skills/layouts/list-page/SKILL.md"
47
+ },
48
+ "composite": {
49
+ "label": "复合控件结构契约",
50
+ "standardsDoc": "standards/component-structures.json"
47
51
  }
48
52
  },
49
53
  "rules": [
@@ -464,6 +468,22 @@
464
468
  "manualReason": "需按组件语义选择 base/small/round 等圆角 token",
465
469
  "scanner": "scanner/rules/semantic.mjs",
466
470
  "skills": ["tokens/index"]
471
+ },
472
+ {
473
+ "id": "R040",
474
+ "category": "composite",
475
+ "severity": "review",
476
+ "title": "未知复合控件结构必须先登记边框与高度契约",
477
+ "rationale": "复合输入可能同时包含 Element 外壳、内部 editor 与 Teleport 浮层;直接套用普通 input 规则会造成固定高度裁切、边框消失或双描边。",
478
+ "appliesTo": [
479
+ "project-owned composite input wrapper",
480
+ ".el-input.el-input__wrapper",
481
+ "picker/multiple/tag wrapper containing Element input"
482
+ ],
483
+ "autoFixable": false,
484
+ "manualReason": "必须核对真实 DOM,明确边框所有者、高度策略、内部无描边层与 Teleport 出口",
485
+ "scanner": "scanner/rules/componentStructure.mjs",
486
+ "skills": ["vendors/jh-components"]
467
487
  }
468
488
  ]
469
489
  }
@@ -70,6 +70,10 @@ textarea 不强制 26px 高度,只继承统一圆角、字体和状态样式
70
70
  复合控件只能由最外层 wrapper 绘制默认、hover、focus、error、disabled 边框;内部编辑 input
71
71
  必须保持无描边,避免边框消失、内容裁切或出现双描边。
72
72
 
73
+ 所有非薄封装复合控件必须登记到 `standards/component-structures.json`,明确根节点、边框
74
+ 所有者、内部无描边层、高度策略、状态与 Teleport 出口,并提供真实 DOM fixture。R040
75
+ 发现疑似未知结构时只要求人工评审,不自动改写;禁止在结构未确认前扩大全局 Element 选择器。
76
+
73
77
  ---
74
78
 
75
79
  ## 规则:紧凑业务表单字号统一为 12px
@@ -75,6 +75,130 @@ html body {
75
75
  line-height: calc(var(--wk-form-control-height) - 2px) !important;
76
76
  }
77
77
 
78
+ // ── 带前/后附加段的输入框 ────────────────────────────────────────────────
79
+ // Element input-group 把输入主体与 append/prepend 分成多个描边节点;平台或
80
+ // 业务局部高度只改其中一段时,就会出现截图中的右侧图标高低、圆角和边框不齐。
81
+ // 仅命中真实 .el-input.el-input-group,由组合根绘制唯一外轮廓,内部只保留分隔线。
82
+ &.el-input.el-input-group {
83
+ display: inline-flex !important;
84
+ align-items: stretch !important;
85
+ height: var(--wk-form-control-height) !important;
86
+ min-height: var(--wk-form-control-height) !important;
87
+ border: 0 !important;
88
+ border-radius: var(--wk-form-control-radius) !important;
89
+ box-sizing: border-box !important;
90
+ overflow: hidden !important;
91
+ background: var(--el-bg-color, #fff) !important;
92
+ box-shadow: 0 0 0 1px var(--el-border-color, #dcdfe6) inset !important;
93
+ transition: box-shadow 0.15s ease !important;
94
+ }
95
+
96
+ &.el-input.el-input-group > .el-input__wrapper {
97
+ flex: 1 1 auto !important;
98
+ min-width: 0 !important;
99
+ height: 100% !important;
100
+ min-height: 0 !important;
101
+ border: 0 !important;
102
+ border-radius: 0 !important;
103
+ background: transparent !important;
104
+ box-shadow: none !important;
105
+ }
106
+
107
+ // jh-ui 配套的 Element Plus 2.2.x 仍可能使用 input 直挂结构。
108
+ &.el-input.el-input-group > .el-input__inner {
109
+ flex: 1 1 auto !important;
110
+ min-width: 0 !important;
111
+ height: 100% !important;
112
+ min-height: 0 !important;
113
+ border: 0 !important;
114
+ border-radius: 0 !important;
115
+ outline: none !important;
116
+ background: transparent !important;
117
+ box-shadow: none !important;
118
+ }
119
+
120
+ &.el-input.el-input-group > .el-input-group__prepend,
121
+ &.el-input.el-input-group > .el-input-group__append {
122
+ display: inline-flex !important;
123
+ flex: 0 0 auto !important;
124
+ align-items: center !important;
125
+ justify-content: center !important;
126
+ width: auto !important;
127
+ height: 100% !important;
128
+ min-height: 0 !important;
129
+ padding: 0 8px !important;
130
+ border: 0 !important;
131
+ border-radius: 0 !important;
132
+ box-sizing: border-box !important;
133
+ color: var(--el-text-color-secondary, #909399) !important;
134
+ background: var(--el-fill-color-light, #f5f7fa) !important;
135
+ box-shadow: none !important;
136
+ }
137
+
138
+ &.el-input.el-input-group > .el-input-group__prepend {
139
+ box-shadow: -1px 0 0 var(--el-border-color, #dcdfe6) inset !important;
140
+ }
141
+
142
+ &.el-input.el-input-group > .el-input-group__append {
143
+ box-shadow: 1px 0 0 var(--el-border-color, #dcdfe6) inset !important;
144
+ }
145
+
146
+ &.el-input.el-input-group
147
+ > :where(.el-input-group__prepend, .el-input-group__append):has(
148
+ > .el-icon:only-child
149
+ ) {
150
+ flex-basis: 32px !important;
151
+ width: 32px !important;
152
+ padding: 0 !important;
153
+ }
154
+
155
+ &.el-input.el-input-group
156
+ > :where(.el-input-group__prepend, .el-input-group__append)
157
+ > .el-icon,
158
+ &.el-input .el-input__prefix-inner > .el-icon,
159
+ &.el-input .el-input__suffix-inner > .el-icon,
160
+ &.el-input .el-input__prefix > .el-icon,
161
+ &.el-input .el-input__suffix > .el-icon {
162
+ width: 14px !important;
163
+ height: 14px !important;
164
+ font-size: 14px !important;
165
+ line-height: 14px !important;
166
+ }
167
+
168
+ &.el-input.el-input-group
169
+ > :where(.el-input-group__prepend, .el-input-group__append)
170
+ > .el-button {
171
+ height: 100% !important;
172
+ min-height: 0 !important;
173
+ margin: 0 -8px !important;
174
+ padding: 0 8px !important;
175
+ border: 0 !important;
176
+ border-radius: 0 !important;
177
+ background: transparent !important;
178
+ box-shadow: none !important;
179
+ }
180
+
181
+ &.el-input.el-input-group:not(.is-disabled):hover {
182
+ box-shadow: 0 0 0 1px var(--el-border-color-hover, #c0c4cc) inset !important;
183
+ }
184
+
185
+ &.el-input.el-input-group:not(.is-disabled):focus-within {
186
+ box-shadow:
187
+ 0 0 0 1.5px var(--el-color-primary, #002a8f) inset,
188
+ 0 0 0 2px rgba(var(--el-color-primary-rgb, 0, 42, 143), 0.1) !important;
189
+ }
190
+
191
+ &.el-input.el-input-group.is-disabled {
192
+ background: var(--el-disabled-bg-color, #f5f7fa) !important;
193
+ box-shadow: 0 0 0 1px var(--el-disabled-border-color, #e4e7ed) inset !important;
194
+ }
195
+
196
+ &.el-input.el-input-group.is-disabled
197
+ > :where(.el-input-group__prepend, .el-input-group__append) {
198
+ color: var(--el-disabled-text-color, #a8abb2) !important;
199
+ background: var(--el-disabled-bg-color, #f5f7fa) !important;
200
+ }
201
+
78
202
  // common-core / jh-ui 有两种数字框 DOM:
79
203
  // A. .el-input-number > .el-input > .el-input__wrapper(社区版)
80
204
  // B. .el-input-number.el-input__wrapper > .el-input(jh 同节点 wrapper)
@@ -217,4 +341,5 @@ html body {
217
341
  box-shadow:
218
342
  0 0 0 2px rgba(var(--el-color-primary-rgb, 0, 42, 143), 0.12) !important;
219
343
  }
344
+
220
345
  }
@@ -612,6 +612,23 @@
612
612
  > .el-input__wrapper {
613
613
  box-shadow: none !important;
614
614
  }
615
+
616
+ // 输入组合框由最外层统一绘制轮廓;错误态必须覆盖其 focus-within 品牌色,
617
+ // 同时清空内部 wrapper,避免 append/prepend 场景出现双描边。
618
+ .el-input.el-input-group:not(.is-disabled),
619
+ .el-input.el-input-group:not(.is-disabled):hover {
620
+ box-shadow: 0 0 0 1px var(--el-color-danger, #f56c6c) inset !important;
621
+ }
622
+
623
+ .el-input.el-input-group:not(.is-disabled):focus-within {
624
+ box-shadow:
625
+ 0 0 0 1.5px var(--el-color-danger, #f56c6c) inset,
626
+ 0 0 0 2px rgba(var(--el-color-danger-rgb, 245, 108, 108), 0.1) !important;
627
+ }
628
+
629
+ .el-input.el-input-group > .el-input__wrapper {
630
+ box-shadow: none !important;
631
+ }
615
632
  }
616
633
  }
617
634
 
@@ -81,3 +81,38 @@ html .drager_row > .slider_row {
81
81
  html .drager_row {
82
82
  min-height: 0;
83
83
  }
84
+
85
+ // 上下分屏只负责裁切布局边界,滚动仍由 AG Grid 内部 viewport 负责。
86
+ // runtime/auto 会仅在分屏 pane 内发现真实 AG Grid 时打上这些结构标记,
87
+ // 从而补齐可收缩高度链;普通内容、普通表格和定制区域不会命中。
88
+ html .drager_row > [data-wl-ui-split-pane] {
89
+ min-height: 0 !important;
90
+ overflow: hidden !important;
91
+ }
92
+
93
+ html .drager_row [data-wl-ui-split-grid-chain] {
94
+ min-height: 0 !important;
95
+ }
96
+
97
+ html
98
+ .drager_row
99
+ [data-wl-ui-split-grid-flex-parent]
100
+ > [data-wl-ui-split-grid-host] {
101
+ flex: 1 1 0 !important;
102
+ height: 0 !important;
103
+ min-height: 0 !important;
104
+ max-height: 100% !important;
105
+ }
106
+
107
+ html .drager_row [data-wl-ui-split-grid-host] {
108
+ min-height: 0 !important;
109
+ max-height: 100% !important;
110
+ }
111
+
112
+ html
113
+ .drager_row
114
+ .ag-grid-table[data-wl-ui-split-grid-host]
115
+ > .ag-root-wrapper {
116
+ height: 100% !important;
117
+ min-height: 0 !important;
118
+ }