@done-coding/admin-core 0.9.0 → 0.9.1-alpha.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/docs/nested-config-paradigm.md +80 -0
- package/es/bridge/theme.mjs +41 -38
- package/es/components/app-layout/AppTheme.vue.mjs +2 -2
- package/es/components/app-layout/AppTheme.vue2.mjs +19 -19
- package/es/components/form/FormItemNestForm.vue.mjs +7 -0
- package/es/components/form/FormItemNestForm.vue2.mjs +49 -0
- package/es/components/form/FormItemNestFormList.vue.mjs +7 -0
- package/es/components/form/FormItemNestFormList.vue2.mjs +137 -0
- package/es/components/form/FormMain.vue.mjs +5 -140
- package/es/components/form/FormMain.vue2.mjs +160 -2
- package/es/components/form/FormSearch.vue.mjs +2 -2
- package/es/components/form/FormSearch.vue2.mjs +43 -42
- package/es/components/form/FormSubmitPanel.vue2.mjs +21 -20
- package/es/components/form/nest-form-item-list.mjs +71 -0
- package/es/components/form/nest-form-item.mjs +42 -0
- package/es/components/form/nest-registry.mjs +7 -0
- package/es/components/form/use-nest-form-list.mjs +22 -0
- package/es/components/form/use-nest-form.mjs +34 -0
- package/es/components/form/use-nest-layout-scale.mjs +14 -0
- package/es/components/form/utils.mjs +77 -61
- package/es/components/modal/ConfirmModal.vue.mjs +1 -2
- package/es/components/modal/ConfirmModal.vue2.mjs +73 -94
- package/es/components/modal/DetailModal.vue.mjs +6 -6
- package/es/components/panel/PanelItemNestForm.vue.mjs +7 -0
- package/es/components/panel/PanelItemNestForm.vue2.mjs +69 -0
- package/es/components/panel/PanelItemNestPanel.vue.mjs +34 -0
- package/es/components/panel/PanelItemNestPanel.vue2.mjs +4 -0
- package/es/components/panel/PanelMain.vue.mjs +2 -2
- package/es/components/panel/PanelMain.vue2.mjs +52 -45
- package/es/components/panel/nest-panel-form.mjs +53 -0
- package/es/components/panel/nest-panel-item.mjs +25 -0
- package/es/index.mjs +182 -153
- package/es/inject/key.mjs +12 -6
- package/es/style.css +1 -1
- package/package.json +2 -2
- package/types/bridge/index.d.ts +3 -3
- package/types/bridge/theme.d.ts +22 -3
- package/types/components/form/FormItemNestForm.vue.d.ts +36 -0
- package/types/components/form/FormItemNestFormList.vue.d.ts +63 -0
- package/types/components/form/FormMain.vue.d.ts +2 -2
- package/types/components/form/FormSearch.vue.d.ts +2 -2
- package/types/components/form/index.d.ts +9 -1
- package/types/components/form/nest-form-item-list.d.ts +63 -0
- package/types/components/form/nest-form-item.d.ts +36 -0
- package/types/components/form/nest-registry.d.ts +22 -0
- package/types/components/form/types.d.ts +2 -0
- package/types/components/form/use-nest-form-list.d.ts +20 -0
- package/types/components/form/use-nest-form.d.ts +26 -0
- package/types/components/form/use-nest-layout-scale.d.ts +17 -0
- package/types/components/form/utils.d.ts +26 -1
- package/types/components/panel/PanelItemNestForm.vue.d.ts +35 -0
- package/types/components/panel/PanelItemNestPanel.vue.d.ts +22 -0
- package/types/components/panel/index.d.ts +5 -1
- package/types/components/panel/nest-panel-form.d.ts +38 -0
- package/types/components/panel/nest-panel-item.d.ts +28 -0
- package/types/components/panel/types.d.ts +2 -0
- package/types/components/table/TableMain.vue.d.ts +2 -2
- package/types/inject/key.d.ts +28 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# 配置化嵌套范式(FormMain 套 FormMain / PanelMain 套 PanelMain / 交叉互套)— 实现纪要
|
|
2
|
+
|
|
3
|
+
> **定位**:**P1/P2/P3 已实现纪要**。本文原为设计提案(design-only),其后 nest 联结组件落地,P1(校验穿透)、P2(Panel 嵌套)、P3(布局 rebase span 值轴)均已实现,**实现走了比初版设想更干净的路**;仅 P3 的**断点选择轴**(容器查询)留后续 opt-in。
|
|
4
|
+
> **实现去向**:4 个联结薄壳(C1 `FormItemNestForm` / C4 `FormItemNestFormList` / C2 `PanelItemNestPanel` / C3 `PanelItemNestForm`)+ 配套 helper(`nestFormItem` / `nestFormItemList` / `nestPanelItem` / `nestPanelForm`)。
|
|
5
|
+
> **上位原则**:KB `paradigm.md` §3.0.1「非顶级子空间挂载薄壳(递归下探二等公民层)」——本文是该范式在 Form/Panel 自嵌套 + 交叉嵌套切片上的工程纪要。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. 范式:薄壳即嵌套(已落地)
|
|
10
|
+
|
|
11
|
+
FormMain / PanelMain **本身没有**「表单套表单 / 面板套面板」的一等 prop 支持,但**也不需要**——两族配置化 item 的渲染出口(`render` / `editorRender`)本就是**开放契约**:返回 `VNode[]` 即可,内容由配置方决定。
|
|
12
|
+
|
|
13
|
+
> 嵌套 = 在一个 item 的 `render`/`editorRender` 里套一层**薄壳**(联结组件),薄壳内部挂一个**新的配置化容器**(子 FormMain / PanelMain)。只要薄壳对外仍满足父容器对该 item 的契约(值、校验、布局),父容器无感知,嵌套即成立。
|
|
14
|
+
|
|
15
|
+
三种形态(无界组合,均已落地):
|
|
16
|
+
- **Form 套 Form**:C1 `FormItemNestForm`(1:1)/ C4 `FormItemNestFormList`(1:N 数组)。
|
|
17
|
+
- **Panel 套 Panel**:C2 `PanelItemNestPanel`(纯展示)。
|
|
18
|
+
- **交叉互套**:C3 `PanelItemNestForm`(Panel 项编辑态内嵌 FormMain)。
|
|
19
|
+
|
|
20
|
+
> KB 视角的本体定位:联结薄壳 = 把**空间二等公民**(子 FormMain/PanelMain,当不了空间根)适配成满足父 item 契约的可嵌挂载件,**非空间一等公民**。见 `paradigm.md` §3.0.1。
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 2. P1 校验穿透 — ✅ 已实现(registry 级联,非初版 validator 桥)
|
|
25
|
+
|
|
26
|
+
### 实际落地
|
|
27
|
+
|
|
28
|
+
- **form 族经 registry 级联**:`FormItemNestForm`(C1)/ `FormItemNestFormList`(C4)经 `useNestForm` / `useNestFormList` 把子 `FormMain` 的 `{ validate, clearValidate, resetFields }` 注册进**最近祖先 FormMain** 的 `exposeMap`(`NestFormExposeMap = shallowReactive<Record<itemKey, NestFormExpose>>`,`nest-registry.ts`)。父顶层一次 `validate/clearValidate/resetFields` 即经 `exposeMap` 级联到子(C4 为聚合 expose + fan-out 遍历 N 行)。
|
|
29
|
+
- **对齐 hideKeyList**:父 FormMain `validate` 按 item key 过滤——整 list 被 hide 时不级联(ADR-8)。
|
|
30
|
+
- **panel 族不接 registry**:panel 是 per-item submit、无父顶层 validate,故 C3 `PanelItemNestForm` 改走组件内**局部 `validateChild`**(提交前自校验,reject 留编辑态);C2 纯展示无校验。
|
|
31
|
+
|
|
32
|
+
> **与初版提案的差异(求真)**:提案曾设想用 item `rules` 的 async `validator` 作「校验穿透桥」。**实现未采用**——registry/exposeMap 级联更干净(无需把子 formInstance 塞进规则闭包,天然对齐 hideKeyList)。初版 validator 桥设想已废弃,不再保留为方向。
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 3. P2 PanelMain 嵌套 — ✅ 已实现
|
|
37
|
+
|
|
38
|
+
- **展示态**(C2 `PanelItemNestPanel`):内层 PanelMain 置 `itemCard=false` → 子项平铺("一项展示多字段"观感,本质潜套 PanelMain);值贯通 = `render` 的 `scope.value` 嵌套对象只读直供子 PanelMain。
|
|
39
|
+
- **编辑态**(C3 `PanelItemNestForm`):经 `editorRender`(优先级高于 `editorConfig`,互斥)挂子 FormMain;`PanelEditSwitch` 进编辑深克隆**草稿**,子 FormMain 绑草稿 in-place,校验通过 `submitFn(草稿) → closeEdit` **回流**真实 data,取消弃草稿。这正是「配置式 `editorConfig` 单字段表达不了的多字段子表单」的合规 escape hatch。
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 4. P3 嵌套后的布局继承(layout 基于父 item 实际宽而非屏幕)— ✅ 已实现(span 值轴;断点选择轴留 opt-in)
|
|
44
|
+
|
|
45
|
+
### 落地(2026-06-13)
|
|
46
|
+
|
|
47
|
+
- 4 联结薄壳现经 `layoutScale` 累乘因子向子 FormMain/PanelMain 传 rebase 因子:`childScale = parentScale × (24 / 父item span)`,子 `resolveFormLayout(span, scale)` 把 span×scale 后 `ceilToTier` 到档集 `{6,8,12,24}`(封顶 24)。**默认开**;helper 加 `rebase?: boolean`(缺省 `true`,`false` = 逆向逃生口原样直透)。
|
|
48
|
+
- 链路:`FormMain`/`PanelMain` 加 prop `layoutScale`(缺省 1)+ provide `NEST_LAYOUT_SCALE_KEY`;薄壳 `useNestLayoutScale` inject 父 scale 叠本层因子;helper 经 `resolveLayoutSpan(layout)` 把父 item 代表 span 传薄壳。
|
|
49
|
+
- 不变量:叶子字段绝对宽 ≈ `(authoredSpan/24) × 屏宽`,与嵌套深度无关。
|
|
50
|
+
- 设计 + worked examples 见 `docs/specs/2026-06-13-045727-moderate-嵌套布局rebase-P3/design.md`。
|
|
51
|
+
|
|
52
|
+
### 解决的缺口
|
|
53
|
+
|
|
54
|
+
外层 item 用窄栅格(如父 `span:12` = 半宽容器)时,子字段 `span` 相对**容器**算百分比 → 嵌套层过挤;rebase 按父 item 实际分配宽放大子 span,维持字段绝对宽与顶级一致。
|
|
55
|
+
|
|
56
|
+
### 已知近似(v1 接受)
|
|
57
|
+
|
|
58
|
+
- 仅修 **span 值轴**;**断点选择轴**(el 的 `xs/sm/md/lg/xl` 由 **window 宽** media query 选档,非容器宽)留后续 opt-in 容器查询治理。
|
|
59
|
+
- 3+ 层且中间层被 ceil/clamp 时,因子用 authored span 略欠精;2 层常见场景精确。
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 5. 状态小结
|
|
64
|
+
|
|
65
|
+
| # | 缺口 | 状态 | 实际落地 / 遗留 |
|
|
66
|
+
|---|---|---|---|
|
|
67
|
+
| P1 | 校验穿透 | ✅ 已实现 | form 族 registry/exposeMap 级联(C1/C4,ADR-1/8);panel 族局部 validateChild(C3)/ 无校验(C2)。初版 validator 桥设想已废 |
|
|
68
|
+
| P2 | Panel 嵌套 | ✅ 已实现 | C2 展示(itemCard 平铺)+ C3 编辑(editorRender 挂子 FormMain + 草稿回流) |
|
|
69
|
+
| P3 | 布局继承 rebase | ✅ 已实现(span 值轴) | layoutScale 累乘链 + ceilToTier 档集;断点选择轴留 opt-in 容器查询 |
|
|
70
|
+
|
|
71
|
+
**遗留边界**:本文不再据 P1/P2/P3 实现展开(已落地,API 见 KB 组件档 + MIGRATION §38);唯一未做项为 P3 的**断点选择轴**(容器查询替代 viewport 媒体断点),留后续 opt-in spec。
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 附:相关源码 / KB 锚点
|
|
76
|
+
|
|
77
|
+
- 联结薄壳源:`packages/core/src/components/form/{FormItemNestForm,FormItemNestFormList}.vue` + `{nest-form-item,nest-form-item-list}.ts`;`packages/core/src/components/panel/{PanelItemNestPanel,PanelItemNestForm}.vue` + `{nest-panel-item,nest-panel-form}.ts`
|
|
78
|
+
- registry 基建:`packages/core/src/components/form/{nest-registry,use-nest-form,use-nest-form-list}.ts`
|
|
79
|
+
- 上位范式 + 组件 API(KB):`~/.claude/knowledge/admin-core/paradigm.md` §3.0.1;`components/{FormItemNestForm,FormItemNestFormList,PanelItemNestPanel,PanelItemNestForm}.md`
|
|
80
|
+
- 嵌套三件套实现 spec(含 ADR-1/5/6/8):`docs/specs/2026-06-12-020608-complex-配置化嵌套联结组件Nest三件套/`
|
package/es/bridge/theme.mjs
CHANGED
|
@@ -1,62 +1,65 @@
|
|
|
1
|
-
import { ref as
|
|
2
|
-
const o = "default",
|
|
1
|
+
import { ref as f, readonly as d } from "vue";
|
|
2
|
+
const o = "default", E = "默认", b = "admin-core-theme", I = (t) => ({
|
|
3
3
|
light: { ...t.light },
|
|
4
4
|
dark: { ...t.dark }
|
|
5
|
-
}),
|
|
6
|
-
const
|
|
7
|
-
if (!
|
|
5
|
+
}), A = (t, c) => {
|
|
6
|
+
const r = t.getItem(c);
|
|
7
|
+
if (!r) return null;
|
|
8
8
|
try {
|
|
9
|
-
const
|
|
10
|
-
return
|
|
9
|
+
const s = JSON.parse(r);
|
|
10
|
+
return s && typeof s == "object" ? s : null;
|
|
11
11
|
} catch {
|
|
12
12
|
return null;
|
|
13
13
|
}
|
|
14
14
|
};
|
|
15
|
-
function
|
|
16
|
-
const
|
|
17
|
-
let
|
|
18
|
-
const a =
|
|
19
|
-
a && (typeof a.themeStyle == "string" && a.themeStyle && (
|
|
20
|
-
const
|
|
15
|
+
function _(t) {
|
|
16
|
+
const c = t.storageKey ?? b, r = /* @__PURE__ */ new Map(), s = f(o), u = f(!1), g = f([]), n = f({});
|
|
17
|
+
let i = o;
|
|
18
|
+
const a = A(t.storage, c);
|
|
19
|
+
a && (typeof a.themeStyle == "string" && a.themeStyle && (i = a.themeStyle), typeof a.themeIsDark == "boolean" && (u.value = a.themeIsDark));
|
|
20
|
+
const h = () => {
|
|
21
21
|
t.storage.setItem(
|
|
22
|
-
|
|
22
|
+
c,
|
|
23
23
|
JSON.stringify({
|
|
24
|
-
themeStyle:
|
|
25
|
-
themeIsDark:
|
|
24
|
+
themeStyle: s.value,
|
|
25
|
+
themeIsDark: u.value
|
|
26
26
|
})
|
|
27
27
|
);
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
},
|
|
28
|
+
}, v = () => {
|
|
29
|
+
g.value = Array.from(r.keys());
|
|
30
|
+
}, m = (e) => {
|
|
31
31
|
t.update("APP_THEME_CONFIG", { light: e.light, dark: e.dark });
|
|
32
|
-
},
|
|
33
|
-
const
|
|
34
|
-
if (!
|
|
35
|
-
const k =
|
|
32
|
+
}, y = (e) => {
|
|
33
|
+
const l = r.get(e);
|
|
34
|
+
if (!l) {
|
|
35
|
+
const k = r.get(o);
|
|
36
36
|
if (!k) return;
|
|
37
|
-
|
|
37
|
+
m(k), s.value = o, h();
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
m(l), s.value = e, h();
|
|
41
41
|
}, S = (e) => {
|
|
42
|
-
|
|
43
|
-
}, p = (e,
|
|
44
|
-
|
|
45
|
-
},
|
|
46
|
-
e
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
u.value = !!e, h();
|
|
43
|
+
}, p = (e, l) => {
|
|
44
|
+
r.set(e, I(l.config)), n.value = { ...n.value, [e]: l.label ?? e }, v(), e === i && s.value !== i && y(e);
|
|
45
|
+
}, L = (e) => {
|
|
46
|
+
if (e === o || !r.delete(e)) return;
|
|
47
|
+
const l = { ...n.value };
|
|
48
|
+
delete l[e], n.value = l, v(), s.value === e && y(o);
|
|
49
|
+
}, D = (e) => n.value[e] ?? e;
|
|
50
|
+
return p(o, { config: t.initConfig, label: E }), {
|
|
49
51
|
theme: {
|
|
50
52
|
add: p,
|
|
51
|
-
remove:
|
|
52
|
-
setStyle:
|
|
53
|
+
remove: L,
|
|
54
|
+
setStyle: y,
|
|
53
55
|
setDark: S,
|
|
54
|
-
list:
|
|
56
|
+
list: d(g),
|
|
57
|
+
labelOf: D
|
|
55
58
|
},
|
|
56
|
-
themeStyle:
|
|
57
|
-
themeIsDark:
|
|
59
|
+
themeStyle: d(s),
|
|
60
|
+
themeIsDark: d(u)
|
|
58
61
|
};
|
|
59
62
|
}
|
|
60
63
|
export {
|
|
61
|
-
|
|
64
|
+
_ as createBridgeThemeHook
|
|
62
65
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import o from "./AppTheme.vue2.mjs";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import p from "../../_virtual/_plugin-vue_export-helper.mjs";
|
|
4
|
-
const
|
|
4
|
+
const e = /* @__PURE__ */ p(o, [["__scopeId", "data-v-1f068b22"]]);
|
|
5
5
|
export {
|
|
6
|
-
|
|
6
|
+
e as default
|
|
7
7
|
};
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import { defineComponent as u, inject as p, computed as n, openBlock as a, createElementBlock as
|
|
1
|
+
import { defineComponent as u, inject as p, computed as n, openBlock as a, createElementBlock as m, createBlock as r, unref as e, withCtx as v, Fragment as d, renderList as h, createCommentVNode as _, createVNode as f } from "vue";
|
|
2
2
|
import { ElSelect as k, ElOption as y, ElSwitch as E } from "element-plus";
|
|
3
3
|
import { Sunny as S, Moon as B } from "@element-plus/icons-vue";
|
|
4
|
-
import { APP_LAYOUT_BRIDGE_KEY as
|
|
5
|
-
const
|
|
4
|
+
import { APP_LAYOUT_BRIDGE_KEY as b } from "../../inject/key.mjs";
|
|
5
|
+
const g = { class: "app-theme" }, O = /* @__PURE__ */ u({
|
|
6
6
|
__name: "AppTheme",
|
|
7
|
-
setup(
|
|
8
|
-
const l = p(
|
|
9
|
-
return (
|
|
10
|
-
i.value.length > 1 ? (a(),
|
|
7
|
+
setup(C) {
|
|
8
|
+
const l = p(b), c = n(() => l.themeIsDark.value), s = n(() => l.themeStyle.value), i = n(() => l.theme.list.value);
|
|
9
|
+
return (D, o) => (a(), m("div", g, [
|
|
10
|
+
i.value.length > 1 ? (a(), r(e(k), {
|
|
11
11
|
key: 0,
|
|
12
12
|
"model-value": s.value,
|
|
13
13
|
class: "app-theme__style-select",
|
|
14
14
|
size: "small",
|
|
15
|
-
onChange: o[0] || (o[0] = (
|
|
15
|
+
onChange: o[0] || (o[0] = (t) => e(l).theme.setStyle(t))
|
|
16
16
|
}, {
|
|
17
17
|
default: v(() => [
|
|
18
|
-
(a(!0),
|
|
19
|
-
key:
|
|
20
|
-
label: e,
|
|
21
|
-
value:
|
|
18
|
+
(a(!0), m(d, null, h(i.value, (t) => (a(), r(e(y), {
|
|
19
|
+
key: t,
|
|
20
|
+
label: e(l).theme.labelOf(t),
|
|
21
|
+
value: t
|
|
22
22
|
}, null, 8, ["label", "value"]))), 128))
|
|
23
23
|
]),
|
|
24
24
|
_: 1
|
|
25
|
-
}, 8, ["model-value"])) :
|
|
26
|
-
f(
|
|
27
|
-
"model-value":
|
|
25
|
+
}, 8, ["model-value"])) : _("", !0),
|
|
26
|
+
f(e(E), {
|
|
27
|
+
"model-value": c.value,
|
|
28
28
|
class: "app-theme__dark-switch",
|
|
29
|
-
"active-action-icon":
|
|
30
|
-
"inactive-action-icon":
|
|
31
|
-
"onUpdate:modelValue": o[1] || (o[1] = (
|
|
29
|
+
"active-action-icon": e(B),
|
|
30
|
+
"inactive-action-icon": e(S),
|
|
31
|
+
"onUpdate:modelValue": o[1] || (o[1] = (t) => e(l).theme.setDark(!!t))
|
|
32
32
|
}, null, 8, ["model-value", "active-action-icon", "inactive-action-icon"])
|
|
33
33
|
]));
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
36
|
export {
|
|
37
|
-
|
|
37
|
+
O as default
|
|
38
38
|
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { defineComponent as s, useModel as m, ref as n, computed as u, openBlock as d, createElementBlock as c, normalizeStyle as i, createVNode as f, unref as p, mergeModels as y } from "vue";
|
|
2
|
+
import h from "./FormMain.vue.mjs";
|
|
3
|
+
import { useNestForm as w } from "./use-nest-form.mjs";
|
|
4
|
+
import { useNestLayoutScale as S } from "./use-nest-layout-scale.mjs";
|
|
5
|
+
const G = /* @__PURE__ */ s({
|
|
6
|
+
name: "FormItemNestForm",
|
|
7
|
+
inheritAttrs: !1,
|
|
8
|
+
__name: "FormItemNestForm",
|
|
9
|
+
props: /* @__PURE__ */ y({
|
|
10
|
+
nestKey: {},
|
|
11
|
+
list: {},
|
|
12
|
+
layout: {},
|
|
13
|
+
rowGutter: {},
|
|
14
|
+
shadowColor: {},
|
|
15
|
+
parentSpan: {},
|
|
16
|
+
rebase: { type: Boolean, default: !0 }
|
|
17
|
+
}, {
|
|
18
|
+
modelValue: { default: () => ({}) },
|
|
19
|
+
modelModifiers: {}
|
|
20
|
+
}),
|
|
21
|
+
emits: ["update:modelValue"],
|
|
22
|
+
setup(e) {
|
|
23
|
+
const t = e, a = S({
|
|
24
|
+
parentSpan: () => t.parentSpan,
|
|
25
|
+
rebase: () => t.rebase
|
|
26
|
+
}), r = m(e, "modelValue"), o = n();
|
|
27
|
+
w({ childRef: o, key: () => t.nestKey });
|
|
28
|
+
const l = u(
|
|
29
|
+
() => t.shadowColor ? { boxShadow: `0 2px 8px ${t.shadowColor}` } : {}
|
|
30
|
+
);
|
|
31
|
+
return (F, x) => (d(), c("div", {
|
|
32
|
+
class: "form-item-nest-form",
|
|
33
|
+
style: i(l.value)
|
|
34
|
+
}, [
|
|
35
|
+
f(h, {
|
|
36
|
+
ref_key: "childRef",
|
|
37
|
+
ref: o,
|
|
38
|
+
list: e.list,
|
|
39
|
+
data: r.value,
|
|
40
|
+
layout: e.layout,
|
|
41
|
+
"layout-scale": p(a),
|
|
42
|
+
rowGutter: e.rowGutter
|
|
43
|
+
}, null, 8, ["list", "data", "layout", "layout-scale", "rowGutter"])
|
|
44
|
+
], 4));
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
export {
|
|
48
|
+
G as default
|
|
49
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { defineComponent as z, computed as m, useModel as A, openBlock as l, createElementBlock as f, normalizeStyle as g, createBlock as y, resolveDynamicComponent as C, createCommentVNode as D, Fragment as $, renderList as j, createElementVNode as E, createVNode as k, unref as v, withCtx as S, createTextVNode as b, toDisplayString as s, mergeModels as G } from "vue";
|
|
2
|
+
import W from "./FormMain.vue.mjs";
|
|
3
|
+
import { useNestFormList as H } from "./use-nest-form-list.mjs";
|
|
4
|
+
import { useNestLayoutScale as O } from "./use-nest-layout-scale.mjs";
|
|
5
|
+
import { generateFormData as q } from "./utils.mjs";
|
|
6
|
+
import F from "../display/ActionBtn.vue.mjs";
|
|
7
|
+
import { getId as J } from "../../utils/id.mjs";
|
|
8
|
+
const ee = /* @__PURE__ */ z({
|
|
9
|
+
name: "FormItemNestFormList",
|
|
10
|
+
inheritAttrs: !1,
|
|
11
|
+
__name: "FormItemNestFormList",
|
|
12
|
+
props: /* @__PURE__ */ G({
|
|
13
|
+
nestKey: {},
|
|
14
|
+
list: {},
|
|
15
|
+
rowKey: {},
|
|
16
|
+
itemFactory: {},
|
|
17
|
+
min: { default: 0 },
|
|
18
|
+
max: { default: 1 / 0 },
|
|
19
|
+
layout: {},
|
|
20
|
+
rowGutter: {},
|
|
21
|
+
addText: { default: "新增" },
|
|
22
|
+
removeText: { default: "删除" },
|
|
23
|
+
headerRender: {},
|
|
24
|
+
footerRender: {},
|
|
25
|
+
shadowColor: {},
|
|
26
|
+
parentSpan: {},
|
|
27
|
+
rebase: { type: Boolean, default: !0 },
|
|
28
|
+
removeConfirm: { type: [Boolean, Object], default: !0 }
|
|
29
|
+
}, {
|
|
30
|
+
modelValue: { default: () => [] },
|
|
31
|
+
modelModifiers: {}
|
|
32
|
+
}),
|
|
33
|
+
emits: ["update:modelValue"],
|
|
34
|
+
setup(o) {
|
|
35
|
+
const t = o, I = m(() => {
|
|
36
|
+
const e = t.removeConfirm;
|
|
37
|
+
if (e !== !1)
|
|
38
|
+
return e && typeof e == "object" ? e : { title: "确认删除该项?", type: "danger" };
|
|
39
|
+
}), R = O({
|
|
40
|
+
parentSpan: () => t.parentSpan,
|
|
41
|
+
rebase: () => t.rebase
|
|
42
|
+
}), i = A(o, "modelValue"), n = m(() => i.value), d = m(() => n.value.length < t.max), p = m(
|
|
43
|
+
() => t.shadowColor ? { boxShadow: `0 2px 8px ${t.shadowColor}` } : {}
|
|
44
|
+
), M = m(
|
|
45
|
+
() => t.shadowColor ? { boxShadow: `0 1px 4px ${t.shadowColor}` } : {}
|
|
46
|
+
), N = () => {
|
|
47
|
+
var e;
|
|
48
|
+
return ((e = t.itemFactory) == null ? void 0 : e.call(t)) ?? q(t.list);
|
|
49
|
+
}, u = /* @__PURE__ */ new WeakMap(), h = (e) => {
|
|
50
|
+
const r = t.rowKey;
|
|
51
|
+
if (r) {
|
|
52
|
+
const a = e == null ? void 0 : e[r];
|
|
53
|
+
if (a != null) return a;
|
|
54
|
+
}
|
|
55
|
+
return u.has(e) || u.set(e, J("formItemNextFormListItem")), u.get(e);
|
|
56
|
+
}, c = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Map(), V = (e) => {
|
|
57
|
+
let r = x.get(e);
|
|
58
|
+
return r || (r = (a) => {
|
|
59
|
+
a ? c.set(e, a) : c.delete(e);
|
|
60
|
+
}, x.set(e, r)), r;
|
|
61
|
+
};
|
|
62
|
+
H({
|
|
63
|
+
rowInstances: () => [...c.values()],
|
|
64
|
+
key: () => t.nestKey
|
|
65
|
+
});
|
|
66
|
+
const w = () => {
|
|
67
|
+
d.value && i.value.push(N());
|
|
68
|
+
}, L = (e) => {
|
|
69
|
+
n.value.length <= t.min || i.value.splice(e, 1);
|
|
70
|
+
}, B = () => {
|
|
71
|
+
var e;
|
|
72
|
+
return (e = t.headerRender) == null ? void 0 : e.call(t, { count: n.value.length, max: t.max });
|
|
73
|
+
}, T = () => {
|
|
74
|
+
var e;
|
|
75
|
+
return (e = t.footerRender) == null ? void 0 : e.call(t, {
|
|
76
|
+
count: n.value.length,
|
|
77
|
+
max: t.max,
|
|
78
|
+
canAdd: d.value,
|
|
79
|
+
add: w
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
return (e, r) => (l(), f("div", {
|
|
83
|
+
class: "form-item-nest-form-list",
|
|
84
|
+
style: g(p.value)
|
|
85
|
+
}, [
|
|
86
|
+
o.headerRender ? (l(), y(C(B), { key: 0 })) : D("", !0),
|
|
87
|
+
(l(!0), f($, null, j(n.value, (a, K) => (l(), f("div", {
|
|
88
|
+
key: h(a),
|
|
89
|
+
class: "form-item-nest-form-list-row"
|
|
90
|
+
}, [
|
|
91
|
+
E("div", {
|
|
92
|
+
class: "form-item-nest-form-list-row-body",
|
|
93
|
+
style: g(M.value)
|
|
94
|
+
}, [
|
|
95
|
+
k(W, {
|
|
96
|
+
ref_for: !0,
|
|
97
|
+
ref: V(h(a)),
|
|
98
|
+
list: o.list,
|
|
99
|
+
data: a,
|
|
100
|
+
layout: o.layout,
|
|
101
|
+
"layout-scale": v(R),
|
|
102
|
+
"row-gutter": o.rowGutter
|
|
103
|
+
}, null, 8, ["list", "data", "layout", "layout-scale", "row-gutter"])
|
|
104
|
+
], 4),
|
|
105
|
+
k(v(F), {
|
|
106
|
+
class: "form-item-nest-form-list-row-remove",
|
|
107
|
+
size: "small",
|
|
108
|
+
text: "",
|
|
109
|
+
type: "danger",
|
|
110
|
+
"confirm-config": I.value,
|
|
111
|
+
disabled: n.value.length <= o.min,
|
|
112
|
+
onClick: () => L(K)
|
|
113
|
+
}, {
|
|
114
|
+
default: S(() => [
|
|
115
|
+
b(s(o.removeText), 1)
|
|
116
|
+
]),
|
|
117
|
+
_: 1
|
|
118
|
+
}, 8, ["confirm-config", "disabled", "onClick"])
|
|
119
|
+
]))), 128)),
|
|
120
|
+
o.footerRender ? (l(), y(C(T), { key: 1 })) : (l(), y(v(F), {
|
|
121
|
+
key: 2,
|
|
122
|
+
size: "small",
|
|
123
|
+
type: "primary",
|
|
124
|
+
disabled: !d.value,
|
|
125
|
+
onClick: w
|
|
126
|
+
}, {
|
|
127
|
+
default: S(() => [
|
|
128
|
+
b(s(o.addText) + "(" + s(n.value.length) + s(o.max === 1 / 0 ? "" : "/" + o.max) + ")", 1)
|
|
129
|
+
]),
|
|
130
|
+
_: 1
|
|
131
|
+
}, 8, ["disabled"]))
|
|
132
|
+
], 4));
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
export {
|
|
136
|
+
ee as default
|
|
137
|
+
};
|
|
@@ -1,142 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
const ue = /* @__PURE__ */ M({
|
|
6
|
-
name: "FormMain",
|
|
7
|
-
inheritAttrs: !0,
|
|
8
|
-
__name: "FormMain",
|
|
9
|
-
props: {
|
|
10
|
-
list: {},
|
|
11
|
-
data: {},
|
|
12
|
-
layout: {},
|
|
13
|
-
rowGutter: { default: 0 }
|
|
14
|
-
},
|
|
15
|
-
emits: ["loadingChange", "visibleChange", "submit"],
|
|
16
|
-
setup(c, { expose: _, emit: D }) {
|
|
17
|
-
const a = c, v = D, o = A(), i = L([]), s = L({}), F = n(() => !!i.value.length), p = n(() => Object.keys(s.value).filter(
|
|
18
|
-
(e) => s.value[e]
|
|
19
|
-
)), R = n(() => a.list.filter((e) => !p.value.includes(e.key))), $ = n(() => R.value.length > 0), G = (e) => e;
|
|
20
|
-
_({
|
|
21
|
-
validate: () => o.value ? new Promise((e, t) => {
|
|
22
|
-
var l;
|
|
23
|
-
(l = o.value) == null || l.validate((r, u) => {
|
|
24
|
-
if (r)
|
|
25
|
-
e();
|
|
26
|
-
else {
|
|
27
|
-
const f = { ...u || {} };
|
|
28
|
-
Object.keys(f).forEach((d) => {
|
|
29
|
-
var E;
|
|
30
|
-
p.value.includes(d) && (console.log(`当前${d}被隐藏,移除校验`, f[d]), delete f[d], (E = o.value) == null || E.clearValidate(d));
|
|
31
|
-
}), Object.keys(f).length === 0 ? e() : t(u);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
}) : Promise.reject(new Error("实例化未完成")),
|
|
35
|
-
resetFields: () => o.value ? o.value.resetFields() : console.error("实例化未完成"),
|
|
36
|
-
clearValidate: (e) => o.value ? o.value.clearValidate(e) : console.error("实例化未完成"),
|
|
37
|
-
generate: () => Z(a.list),
|
|
38
|
-
parse: (e) => Y(e, a.list),
|
|
39
|
-
stringify: () => X(a.data, a.list)
|
|
40
|
-
});
|
|
41
|
-
const g = n(() => a.list), k = n(() => g.value.reduce((e, t) => (t.rules && (typeof t.rules == "function" ? e[t.key] = t.rules({
|
|
42
|
-
data: a.data,
|
|
43
|
-
config: t
|
|
44
|
-
}) : e[t.key] = t.rules), e), {})), w = n(() => i.value.reduce(
|
|
45
|
-
(e, t) => (e[t.key] = [
|
|
46
|
-
{
|
|
47
|
-
validator: () => [new Error(`${t.label}${t.message}`)]
|
|
48
|
-
}
|
|
49
|
-
], e),
|
|
50
|
-
{}
|
|
51
|
-
)), I = n(() => {
|
|
52
|
-
const e = Object.keys(k.value), t = Object.keys(w.value);
|
|
53
|
-
return [...new Set(e.concat(t))].reduce((r, u) => (r[u] = [
|
|
54
|
-
...k.value[u] || [],
|
|
55
|
-
...w.value[u] || []
|
|
56
|
-
], r), {});
|
|
57
|
-
});
|
|
58
|
-
B(W, ({ key: e, message: t }) => {
|
|
59
|
-
if (!e)
|
|
60
|
-
return console.error("更新状态未传入key, 此处忽略");
|
|
61
|
-
const l = i.value.findIndex((r) => r.key === e);
|
|
62
|
-
l === -1 ? t && i.value.push({
|
|
63
|
-
key: e,
|
|
64
|
-
message: t,
|
|
65
|
-
label: a.list.find((r) => r.key === e).label
|
|
66
|
-
}) : t ? i.value.splice(l, 1, {
|
|
67
|
-
key: e,
|
|
68
|
-
message: t,
|
|
69
|
-
label: a.list.find((r) => r.key === e).label
|
|
70
|
-
}) : i.value.splice(l, 1);
|
|
71
|
-
});
|
|
72
|
-
const K = ({
|
|
73
|
-
status: e,
|
|
74
|
-
config: { key: t }
|
|
75
|
-
}) => {
|
|
76
|
-
(s.value[t] || !1) !== e && (s.value[t] = e);
|
|
77
|
-
}, C = (e) => ({
|
|
78
|
-
...x(a.layout),
|
|
79
|
-
...x(e)
|
|
80
|
-
});
|
|
81
|
-
return y(
|
|
82
|
-
g,
|
|
83
|
-
(e) => {
|
|
84
|
-
const t = e.map((l) => l.key);
|
|
85
|
-
Object.keys(s.value).forEach((l) => {
|
|
86
|
-
t.includes(l) || delete s.value[l];
|
|
87
|
-
});
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
immediate: !0
|
|
91
|
-
}
|
|
92
|
-
), y(F, () => {
|
|
93
|
-
v("loadingChange", F.value);
|
|
94
|
-
}), y(
|
|
95
|
-
$,
|
|
96
|
-
(e) => {
|
|
97
|
-
v("visibleChange", e);
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
immediate: !0
|
|
101
|
-
}
|
|
102
|
-
), (e, t) => (h(), O(b(z), {
|
|
103
|
-
ref_key: "elForm",
|
|
104
|
-
ref: o,
|
|
105
|
-
model: c.data,
|
|
106
|
-
rules: I.value
|
|
107
|
-
}, {
|
|
108
|
-
default: m(() => [
|
|
109
|
-
V(b(J), { gutter: c.rowGutter }, {
|
|
110
|
-
default: m(() => [
|
|
111
|
-
(h(!0), H(N, null, P(g.value, (l) => T((h(), O(b(Q), j({
|
|
112
|
-
key: l.key
|
|
113
|
-
}, { ref_for: !0 }, C(l.layout)), {
|
|
114
|
-
default: m(() => [
|
|
115
|
-
V(U, {
|
|
116
|
-
data: c.data,
|
|
117
|
-
config: G(l),
|
|
118
|
-
onViewHideChange: K,
|
|
119
|
-
onSubmit: t[0] || (t[0] = (r) => v("submit", r))
|
|
120
|
-
}, {
|
|
121
|
-
default: m((r) => [
|
|
122
|
-
S(e.$slots, l.key, j({ ref_for: !0 }, r))
|
|
123
|
-
]),
|
|
124
|
-
_: 2
|
|
125
|
-
}, 1032, ["data", "config"])
|
|
126
|
-
]),
|
|
127
|
-
_: 2
|
|
128
|
-
}, 1040)), [
|
|
129
|
-
[q, !(s.value[l.key] ?? !1)]
|
|
130
|
-
])), 128)),
|
|
131
|
-
S(e.$slots, "default", { mergeLayout: C })
|
|
132
|
-
]),
|
|
133
|
-
_: 3
|
|
134
|
-
}, 8, ["gutter"])
|
|
135
|
-
]),
|
|
136
|
-
_: 3
|
|
137
|
-
}, 8, ["model", "rules"]));
|
|
138
|
-
}
|
|
139
|
-
});
|
|
1
|
+
import o from "./FormMain.vue2.mjs";
|
|
2
|
+
/* empty css */
|
|
3
|
+
import r from "../../_virtual/_plugin-vue_export-helper.mjs";
|
|
4
|
+
const p = /* @__PURE__ */ r(o, [["__scopeId", "data-v-8ad14c45"]]);
|
|
140
5
|
export {
|
|
141
|
-
|
|
6
|
+
p as default
|
|
142
7
|
};
|