@tmagic/form 1.8.0-beta.13 → 1.8.0-beta.14
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/dist/es/Form.vue_vue_type_script_setup_true_lang.js +51 -16
- package/dist/es/FormDialog.vue_vue_type_script_setup_true_lang.js +12 -5
- package/dist/es/FormDrawer.vue_vue_type_script_setup_true_lang.js +38 -12
- package/dist/es/containers/Container.vue_vue_type_script_setup_true_lang.js +23 -17
- package/dist/es/containers/GroupList.vue_vue_type_script_setup_true_lang.js +6 -5
- package/dist/es/containers/GroupListItem.vue_vue_type_script_setup_true_lang.js +41 -31
- package/dist/es/containers/Panel.vue_vue_type_script_setup_true_lang.js +16 -10
- package/dist/es/containers/table/ActionsColumn.vue_vue_type_script_setup_true_lang.js +13 -6
- package/dist/es/containers/table/Table.vue_vue_type_script_setup_true_lang.js +4 -2
- package/dist/es/containers/table/useTableColumns.js +5 -1
- package/dist/es/containers/table-group-list/TableGroupList.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/es/fields/Cascader.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/es/fields/Checkbox.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/CheckboxGroup.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/es/fields/ColorPicker.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/Date.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/es/fields/DateTime.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/es/fields/Daterange.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/es/fields/Display.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/es/fields/DynamicField.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/Link.vue_vue_type_script_setup_true_lang.js +29 -7
- package/dist/es/fields/Number.vue_vue_type_script_setup_true_lang.js +7 -2
- package/dist/es/fields/NumberRange.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/RadioGroup.vue_vue_type_script_setup_true_lang.js +19 -9
- package/dist/es/fields/Select.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/Switch.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/Text.vue_vue_type_script_setup_true_lang.js +112 -77
- package/dist/es/fields/Textarea.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/Time.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/Timerange.vue_vue_type_script_setup_true_lang.js +6 -3
- package/dist/es/index.js +3 -3
- package/dist/es/plugin.js +3 -1
- package/dist/es/style.css +122 -8
- package/dist/es/submitForm.js +2 -8
- package/dist/es/utils/config.js +4 -1
- package/dist/es/utils/form.js +33 -3
- package/dist/es/utils/typeMatch.js +1 -1
- package/dist/style.css +122 -8
- package/dist/themes/magic-admin.css +499 -0
- package/dist/tmagic-form.umd.cjs +541 -296
- package/package.json +4 -4
- package/src/Form.vue +71 -18
- package/src/FormDialog.vue +14 -3
- package/src/FormDrawer.vue +40 -12
- package/src/containers/Container.vue +16 -5
- package/src/containers/GroupList.vue +1 -1
- package/src/containers/GroupListItem.vue +28 -22
- package/src/containers/Panel.vue +10 -3
- package/src/containers/table/ActionsColumn.vue +10 -4
- package/src/containers/table/Table.vue +1 -0
- package/src/containers/table/useTableColumns.ts +7 -3
- package/src/containers/table-group-list/TableGroupList.vue +7 -1
- package/src/fields/Link.vue +16 -3
- package/src/fields/Number.vue +2 -1
- package/src/fields/RadioGroup.vue +21 -6
- package/src/fields/Text.vue +43 -19
- package/src/plugin.ts +3 -0
- package/src/submitForm.ts +5 -11
- package/src/theme/container.scss +3 -0
- package/src/theme/fieldset.scss +51 -0
- package/src/theme/form.scss +6 -0
- package/src/theme/group-list.scss +9 -7
- package/src/theme/index.scss +1 -0
- package/src/theme/link.scss +17 -0
- package/src/theme/panel.scss +1 -1
- package/src/theme/radio-group.scss +23 -0
- package/src/theme/tabs.scss +2 -2
- package/src/theme/text.scss +38 -0
- package/src/theme/themes/magic-admin/index.scss +95 -0
- package/src/utils/config.ts +7 -1
- package/src/utils/form.ts +37 -0
- package/types/index.d.ts +64 -3
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.8.0-beta.
|
|
2
|
+
"version": "1.8.0-beta.14",
|
|
3
3
|
"name": "@tmagic/form",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"vue": "^3.5.40",
|
|
54
54
|
"typescript": "^6.0.3",
|
|
55
|
-
"@tmagic/
|
|
56
|
-
"@tmagic/
|
|
57
|
-
"@tmagic/
|
|
55
|
+
"@tmagic/utils": "1.8.0-beta.14",
|
|
56
|
+
"@tmagic/design": "1.8.0-beta.14",
|
|
57
|
+
"@tmagic/form-schema": "1.8.0-beta.14"
|
|
58
58
|
},
|
|
59
59
|
"peerDependenciesMeta": {
|
|
60
60
|
"typescript": {
|
package/src/Form.vue
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<TMagicForm
|
|
3
|
-
class="
|
|
3
|
+
:class="[
|
|
4
|
+
'm-form',
|
|
5
|
+
effectiveTheme ? `m-form--${effectiveTheme}` : '',
|
|
6
|
+
effectiveTheme ? `m-theme--${effectiveTheme}` : '',
|
|
7
|
+
]"
|
|
4
8
|
ref="tMagicForm"
|
|
5
9
|
:model="values"
|
|
6
10
|
:label-width="labelWidth"
|
|
@@ -32,15 +36,27 @@
|
|
|
32
36
|
</template>
|
|
33
37
|
|
|
34
38
|
<script setup lang="ts">
|
|
35
|
-
import {
|
|
39
|
+
import {
|
|
40
|
+
computed,
|
|
41
|
+
inject,
|
|
42
|
+
nextTick,
|
|
43
|
+
provide,
|
|
44
|
+
reactive,
|
|
45
|
+
ref,
|
|
46
|
+
shallowRef,
|
|
47
|
+
toRaw,
|
|
48
|
+
useTemplateRef,
|
|
49
|
+
watch,
|
|
50
|
+
watchEffect,
|
|
51
|
+
} from 'vue';
|
|
36
52
|
import { cloneDeep, isEqual } from 'lodash-es';
|
|
37
53
|
|
|
38
|
-
import { TMagicForm, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
|
|
54
|
+
import { M_THEME_KEY, TMagicForm, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
|
|
39
55
|
import { setValueByKeyPath } from '@tmagic/utils';
|
|
40
56
|
|
|
41
57
|
import Container from './containers/Container.vue';
|
|
42
58
|
import { getConfig } from './utils/config';
|
|
43
|
-
import { initValue } from './utils/form';
|
|
59
|
+
import { applyExtendState, initValue } from './utils/form';
|
|
44
60
|
import type {
|
|
45
61
|
ChangeRecord,
|
|
46
62
|
ContainerChangeEventData,
|
|
@@ -116,6 +132,15 @@ const props = withDefaults(
|
|
|
116
132
|
* 通过 provide 下发,对整棵表单的所有层级 Container 生效,只需在 MForm 这一层传一次。
|
|
117
133
|
*/
|
|
118
134
|
selfDiffFieldTypes?: string[] | ((_defaultTypes: string[]) => string[]);
|
|
135
|
+
/**
|
|
136
|
+
* 主题名称:对应 `packages/form/src/theme/themes/<theme>/index.scss` 的目录名。
|
|
137
|
+
*
|
|
138
|
+
* 设置后会在表单根元素上追加 `m-form--<theme>` 修饰类,配合按需引入
|
|
139
|
+
* `@tmagic/form/dist/themes/<theme>.css` 即可启用主题样式。
|
|
140
|
+
*
|
|
141
|
+
* 例如:`<MForm theme="magic-admin" />` + `import '@tmagic/form/dist/themes/magic-admin.css'`。
|
|
142
|
+
*/
|
|
143
|
+
theme?: string;
|
|
119
144
|
}>(),
|
|
120
145
|
{
|
|
121
146
|
config: () => [],
|
|
@@ -149,6 +174,27 @@ const fields = new Map<string, any>();
|
|
|
149
174
|
|
|
150
175
|
const requestFuc = getConfig('request') as Function;
|
|
151
176
|
|
|
177
|
+
/**
|
|
178
|
+
* 当前表单生效的主题名称:
|
|
179
|
+
* - 优先用本组件自己的 `props.theme`;
|
|
180
|
+
* - 没设置时回退到最近祖先 `<MEditor>` / `<MForm>` provide 的主题,便于内嵌于编辑器
|
|
181
|
+
* 时自动跟随外层主题,无需在每个 `MForm` 上重复传 `theme`。
|
|
182
|
+
*
|
|
183
|
+
* 同时把合并后的值再 provide 出去(见下方 `provide(M_THEME_KEY, ...)`),让 form 子树
|
|
184
|
+
* 里再嵌套的 portal 组件(`TMagicPopover` 等)依然能拿到非空主题。
|
|
185
|
+
*/
|
|
186
|
+
const ancestorTheme = inject(M_THEME_KEY, null);
|
|
187
|
+
const effectiveTheme = computed(() => props.theme || ancestorTheme?.value || '');
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* 拼到 `formState.popperClass` 上的主题修饰类(仅 `m-theme--<theme>`,
|
|
191
|
+
* 不带 `m-form` / `m-editor` 前缀,因为 Element Plus 弹层节点本身既不是 form 也不是 editor)。
|
|
192
|
+
*
|
|
193
|
+
* 这条类会随所有读 `mForm.popperClass` 的字段(Select / DateTime / Cascader 等)下发到
|
|
194
|
+
* Element Plus 的 `popper-class`,让 portal 节点也命中 `m-theme--<theme>` 上的 CSS 变量。
|
|
195
|
+
*/
|
|
196
|
+
const themeClass = computed(() => (effectiveTheme.value ? `m-theme--${effectiveTheme.value}` : ''));
|
|
197
|
+
|
|
152
198
|
/**
|
|
153
199
|
* formState 实现说明:
|
|
154
200
|
*
|
|
@@ -165,13 +211,21 @@ const requestFuc = getConfig('request') as Function;
|
|
|
165
211
|
* 把最新值刷进 formState。
|
|
166
212
|
* - accessor 描述符(`{ get stage() { return ... } }`)按原样写入,调用方可以控制
|
|
167
213
|
* 读时求值,每次读取都会重新执行 getter。
|
|
214
|
+
*
|
|
215
|
+
* 4. `popperClass` 会自动拼接 `themeClass`:调用方传入的 `popperClass` + 当前主题
|
|
216
|
+
* 修饰类(含祖先 `<MEditor>` provide 的主题)。这样所有透传到 Element Plus 弹层
|
|
217
|
+
* `popper-class` 的字段(Select / DateTime / Cascader 等)能自带主题作用域。
|
|
168
218
|
*/
|
|
169
219
|
const formState: FormState = reactive<FormState>({
|
|
170
220
|
get keyProp() {
|
|
171
221
|
return props.keyProp;
|
|
172
222
|
},
|
|
173
223
|
get popperClass() {
|
|
174
|
-
|
|
224
|
+
const userClass = props.popperClass ?? '';
|
|
225
|
+
const tc = themeClass.value;
|
|
226
|
+
if (!userClass) return tc;
|
|
227
|
+
if (!tc) return userClass;
|
|
228
|
+
return `${userClass} ${tc}`;
|
|
175
229
|
},
|
|
176
230
|
get config() {
|
|
177
231
|
return props.config;
|
|
@@ -222,11 +276,10 @@ const formState: FormState = reactive<FormState>({
|
|
|
222
276
|
* 这里不再重复同步;因此 `props.initValues` 这类高频变化也不会再触发
|
|
223
277
|
* `extendState` 重跑(旧版的性能问题修复点)。
|
|
224
278
|
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
* 可以自行控制读时求值;强制 `configurable: true` 以便下一次重跑可再 define。
|
|
279
|
+
* 实现细节:合并逻辑统一收口在 `applyExtendState`(utils/form)——
|
|
280
|
+
* data 描述符走 reactive proxy 的 set 触发依赖通知(与旧版「逐项赋值」语义等价),
|
|
281
|
+
* accessor 描述符按原样 defineProperty 支持读时求值;
|
|
282
|
+
* props 派生的只读 getter 字段(keyProp 等)以普通字段形式返回时会被跳过并告警。
|
|
230
283
|
*/
|
|
231
284
|
watchEffect(async (onCleanup) => {
|
|
232
285
|
const { extendState } = props;
|
|
@@ -246,18 +299,18 @@ watchEffect(async (onCleanup) => {
|
|
|
246
299
|
}
|
|
247
300
|
if (stale) return;
|
|
248
301
|
|
|
249
|
-
|
|
250
|
-
if ('value' in descriptor) {
|
|
251
|
-
(formState as any)[key] = (state as any)[key];
|
|
252
|
-
} else {
|
|
253
|
-
descriptor.configurable = true;
|
|
254
|
-
Object.defineProperty(formState, key, descriptor);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
302
|
+
applyExtendState(formState, state);
|
|
257
303
|
});
|
|
258
304
|
|
|
259
305
|
provide('mForm', formState);
|
|
260
306
|
|
|
307
|
+
/**
|
|
308
|
+
* 把生效主题(自身或祖先)再 provide 出去,供 form 子树内含 `Teleport` 的组件
|
|
309
|
+
* (如 `TMagicPopover`)在传送目标上挂 `m-theme--<theme>` 类。
|
|
310
|
+
* 详见 `@tmagic/design/theme.ts`。
|
|
311
|
+
*/
|
|
312
|
+
provide(M_THEME_KEY, effectiveTheme);
|
|
313
|
+
provide('formInline', props.inline);
|
|
261
314
|
// 对比相关配置单独通过 provide 下发,所有层级的 Container 通过 inject 获取,无需逐层透传 prop。
|
|
262
315
|
// 用 getter 对象保证读取时回到最新的 props 值,维持响应式。
|
|
263
316
|
provide(FORM_DIFF_CONFIG_KEY, {
|
package/src/FormDialog.vue
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<TMagicDialog
|
|
3
3
|
v-model="dialogVisible"
|
|
4
|
-
class="m-form-dialog"
|
|
4
|
+
:class="['m-form-dialog', effectiveTheme ? `m-theme--${effectiveTheme}` : '']"
|
|
5
5
|
top="20px"
|
|
6
6
|
append-to-body
|
|
7
7
|
:title="title"
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
:use-field-text-in-error="useFieldTextInError"
|
|
35
35
|
:type-match-valid="typeMatchValid"
|
|
36
36
|
:extend-state="extendState"
|
|
37
|
+
:theme="effectiveTheme"
|
|
37
38
|
@change="changeHandler"
|
|
38
39
|
></Form>
|
|
39
40
|
<slot></slot>
|
|
@@ -66,9 +67,9 @@
|
|
|
66
67
|
</template>
|
|
67
68
|
|
|
68
69
|
<script setup lang="ts">
|
|
69
|
-
import { computed, ref } from 'vue';
|
|
70
|
+
import { computed, inject, provide, ref } from 'vue';
|
|
70
71
|
|
|
71
|
-
import { TMagicButton, TMagicCol, TMagicDialog, TMagicRow } from '@tmagic/design';
|
|
72
|
+
import { M_THEME_KEY, TMagicButton, TMagicCol, TMagicDialog, TMagicRow } from '@tmagic/design';
|
|
72
73
|
|
|
73
74
|
import Form from './Form.vue';
|
|
74
75
|
import { ContainerChangeEventData, FormConfig, FormState, FormValue, StepConfig } from './schema';
|
|
@@ -104,6 +105,12 @@ const props = withDefaults(
|
|
|
104
105
|
useFieldTextInError?: boolean;
|
|
105
106
|
/** 透传给内部 `MForm`,用于扩展 `formState`(如注入 `$message` / `$store` 等) */
|
|
106
107
|
extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
|
|
108
|
+
/**
|
|
109
|
+
* 主题名。优先级:传入 `theme` prop > 祖先 `provide(M_THEME_KEY)` > 空串。
|
|
110
|
+
* 计算结果会再次 `provide` 出去,使得 Dialog 被 Teleport 到 body 后,内部子树
|
|
111
|
+
* (包括 `MForm` 以及更深的 popover / dropdown)仍能拿到主题。
|
|
112
|
+
*/
|
|
113
|
+
theme?: string;
|
|
107
114
|
}>(),
|
|
108
115
|
{
|
|
109
116
|
config: () => [],
|
|
@@ -118,6 +125,10 @@ const props = withDefaults(
|
|
|
118
125
|
},
|
|
119
126
|
);
|
|
120
127
|
|
|
128
|
+
const ancestorTheme = inject(M_THEME_KEY, null);
|
|
129
|
+
const effectiveTheme = computed(() => props.theme || ancestorTheme?.value || '');
|
|
130
|
+
provide(M_THEME_KEY, effectiveTheme);
|
|
131
|
+
|
|
121
132
|
const emit = defineEmits(['close', 'submit', 'error', 'change']);
|
|
122
133
|
|
|
123
134
|
const form = ref<InstanceType<typeof Form>>();
|
package/src/FormDrawer.vue
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<TMagicDrawer
|
|
3
|
-
class="m-form-drawer"
|
|
3
|
+
:class="['m-form-drawer', effectiveTheme ? `m-theme--${effectiveTheme}` : '']"
|
|
4
4
|
ref="drawer"
|
|
5
|
-
v-model="
|
|
5
|
+
v-model="dialogVisible"
|
|
6
6
|
:title="title"
|
|
7
7
|
:close-on-press-escape="closeOnPressEscape"
|
|
8
8
|
:append-to-body="true"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
@close="closeHandler"
|
|
17
17
|
@closed="closedHandler"
|
|
18
18
|
>
|
|
19
|
-
<div v-if="
|
|
19
|
+
<div v-if="dialogVisible" ref="drawerBody" class="m-drawer-body">
|
|
20
20
|
<Form
|
|
21
21
|
ref="form"
|
|
22
22
|
:size="size"
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
:use-field-text-in-error="useFieldTextInError"
|
|
32
32
|
:type-match-valid="typeMatchValid"
|
|
33
33
|
:extend-state="extendState"
|
|
34
|
+
:theme="effectiveTheme"
|
|
34
35
|
@change="changeHandler"
|
|
35
36
|
></Form>
|
|
36
37
|
<slot></slot>
|
|
@@ -57,18 +58,18 @@
|
|
|
57
58
|
</template>
|
|
58
59
|
|
|
59
60
|
<script setup lang="ts">
|
|
60
|
-
import { ref, watchEffect } from 'vue';
|
|
61
|
+
import { computed, inject, provide, ref, watchEffect } from 'vue';
|
|
61
62
|
|
|
62
|
-
import { TMagicButton, TMagicCol, TMagicDrawer, TMagicRow } from '@tmagic/design';
|
|
63
|
+
import { M_THEME_KEY, TMagicButton, TMagicCol, TMagicDrawer, TMagicRow } from '@tmagic/design';
|
|
63
64
|
|
|
64
65
|
import Form from './Form.vue';
|
|
65
66
|
import type { ContainerChangeEventData, FormConfig, FormState, FormValue } from './schema';
|
|
66
67
|
|
|
67
68
|
defineOptions({
|
|
68
|
-
name: '
|
|
69
|
+
name: 'MFormDrawer',
|
|
69
70
|
});
|
|
70
71
|
|
|
71
|
-
withDefaults(
|
|
72
|
+
const props = withDefaults(
|
|
72
73
|
defineProps<{
|
|
73
74
|
config?: FormConfig;
|
|
74
75
|
values?: Object;
|
|
@@ -92,6 +93,12 @@ withDefaults(
|
|
|
92
93
|
beforeClose?: (_done: (_cancel?: boolean) => void) => void;
|
|
93
94
|
/** 透传给内部 `MForm`,用于扩展 `formState`(如注入 `$message` / `$store` 等) */
|
|
94
95
|
extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
|
|
96
|
+
/**
|
|
97
|
+
* 主题名。优先级:传入 `theme` prop > 祖先 `provide(M_THEME_KEY)` > 空串。
|
|
98
|
+
* 计算结果会再次 `provide` 出去,使得 Drawer 被 Teleport 到 body 后,内部子树
|
|
99
|
+
* (包括 `MForm` 以及更深的 popover / dropdown)仍能拿到主题。
|
|
100
|
+
*/
|
|
101
|
+
theme?: string;
|
|
95
102
|
}>(),
|
|
96
103
|
{
|
|
97
104
|
closeOnPressEscape: true,
|
|
@@ -102,12 +109,16 @@ withDefaults(
|
|
|
102
109
|
},
|
|
103
110
|
);
|
|
104
111
|
|
|
112
|
+
const ancestorTheme = inject(M_THEME_KEY, null);
|
|
113
|
+
const effectiveTheme = computed(() => props.theme || ancestorTheme?.value || '');
|
|
114
|
+
provide(M_THEME_KEY, effectiveTheme);
|
|
115
|
+
|
|
105
116
|
const emit = defineEmits(['close', 'closed', 'submit', 'error', 'change', 'open', 'opened']);
|
|
106
117
|
|
|
107
118
|
const drawer = ref<InstanceType<typeof TMagicDrawer>>();
|
|
108
119
|
const form = ref<InstanceType<typeof Form>>();
|
|
109
120
|
const drawerBody = ref<HTMLDivElement>();
|
|
110
|
-
const
|
|
121
|
+
const dialogVisible = ref(false);
|
|
111
122
|
const saveFetch = ref(false);
|
|
112
123
|
const bodyHeight = ref(0);
|
|
113
124
|
|
|
@@ -148,25 +159,42 @@ const closedHandler = () => {
|
|
|
148
159
|
};
|
|
149
160
|
|
|
150
161
|
const show = () => {
|
|
151
|
-
|
|
162
|
+
dialogVisible.value = true;
|
|
152
163
|
};
|
|
153
164
|
|
|
154
165
|
const hide = () => {
|
|
155
|
-
|
|
166
|
+
dialogVisible.value = false;
|
|
167
|
+
};
|
|
168
|
+
const close = () => {
|
|
169
|
+
dialogVisible.value = false;
|
|
170
|
+
};
|
|
171
|
+
const cancel = () => {
|
|
172
|
+
hide();
|
|
156
173
|
};
|
|
157
|
-
|
|
158
174
|
/** 用于关闭 Drawer, 该方法会调用传入的 before-close 方法 */
|
|
159
175
|
const handleClose = () => {
|
|
160
176
|
drawer.value?.handleClose();
|
|
161
177
|
};
|
|
162
178
|
|
|
179
|
+
const save = async () => {
|
|
180
|
+
try {
|
|
181
|
+
const changeRecords = [...(form.value?.changeRecords || [])];
|
|
182
|
+
const values = await form.value?.submitForm();
|
|
183
|
+
emit('submit', values, { changeRecords });
|
|
184
|
+
} catch (e) {
|
|
185
|
+
emit('error', e);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
163
189
|
defineExpose({
|
|
164
190
|
form,
|
|
165
191
|
saveFetch,
|
|
166
192
|
bodyHeight,
|
|
167
|
-
|
|
193
|
+
close,
|
|
168
194
|
show,
|
|
169
195
|
hide,
|
|
196
|
+
save,
|
|
197
|
+
cancel,
|
|
170
198
|
handleClose,
|
|
171
199
|
});
|
|
172
200
|
</script>
|
|
@@ -35,6 +35,9 @@
|
|
|
35
35
|
:label-title="config.labelTitle"
|
|
36
36
|
:text="text"
|
|
37
37
|
></FormLabel>
|
|
38
|
+
<span class="m-form-tip m-form-title-extra" v-if="config.titleExtra && config.labelPosition === 'top'">
|
|
39
|
+
{{ config.titleExtra }}</span
|
|
40
|
+
>
|
|
38
41
|
</slot>
|
|
39
42
|
</template>
|
|
40
43
|
|
|
@@ -222,17 +225,23 @@
|
|
|
222
225
|
</template>
|
|
223
226
|
</template>
|
|
224
227
|
|
|
225
|
-
<div
|
|
226
|
-
<TMagicButton
|
|
227
|
-
|
|
228
|
-
|
|
228
|
+
<div class="m-form-container-expand" v-if="config.expand && type !== 'fieldset'">
|
|
229
|
+
<TMagicButton
|
|
230
|
+
type="primary"
|
|
231
|
+
size="small"
|
|
232
|
+
:disabled="false"
|
|
233
|
+
link
|
|
234
|
+
@click="expandHandler"
|
|
235
|
+
:icon="expand ? ArrowUp : ArrowDown"
|
|
236
|
+
>{{ expand ? '收起配置' : '展开更多配置' }}</TMagicButton
|
|
237
|
+
>
|
|
229
238
|
</div>
|
|
230
239
|
</div>
|
|
231
240
|
</template>
|
|
232
241
|
|
|
233
242
|
<script setup lang="ts">
|
|
234
243
|
import { computed, inject, readonly, ref, toRaw, watch, watchEffect } from 'vue';
|
|
235
|
-
import { WarningFilled } from '@element-plus/icons-vue';
|
|
244
|
+
import { ArrowDown, ArrowUp, WarningFilled } from '@element-plus/icons-vue';
|
|
236
245
|
import { isEqual } from 'lodash-es';
|
|
237
246
|
|
|
238
247
|
import { TMagicButton, TMagicFormItem, TMagicIcon, TMagicTooltip } from '@tmagic/design';
|
|
@@ -440,8 +449,10 @@ const formItemProps = computed(() => ({
|
|
|
440
449
|
prop: itemProp.value,
|
|
441
450
|
labelWidth: itemLabelWidth.value,
|
|
442
451
|
labelPosition: props.config.labelPosition,
|
|
452
|
+
|
|
443
453
|
rules: rule.value,
|
|
444
454
|
extra: filterFunction(mForm, props.config.extra, props),
|
|
455
|
+
extraTips: props.config.extraTips,
|
|
445
456
|
}));
|
|
446
457
|
|
|
447
458
|
const itemLabelWidth = computed(() => props.config.labelWidth ?? props.labelWidth);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="m-fields-group-list">
|
|
3
3
|
<div v-if="config.extra" v-html="config.extra" style="color: rgba(0, 0, 0, 0.45)"></div>
|
|
4
4
|
<div v-if="!model[name] || !model[name].length" class="el-table__empty-block">
|
|
5
|
-
<span class="el-table__empty-text t-table__empty"
|
|
5
|
+
<span class="el-table__empty-text t-table__empty">暂无{{ config.titlePrefix || '' }}数据</span>
|
|
6
6
|
</div>
|
|
7
7
|
|
|
8
8
|
<MFieldsGroupListItem
|
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<TMagicCard class="m-fields-group-list-item" :body-style="{ display: expand ? 'block' : 'none' }">
|
|
2
|
+
<TMagicCard class="m-fields-group-list-item" :flat="config.flat" :body-style="{ display: expand ? 'block' : 'none' }">
|
|
3
3
|
<template #header>
|
|
4
|
-
<div>
|
|
5
|
-
<TMagicButton link :disabled="disabled" @click="expandHandler">
|
|
6
|
-
<TMagicIcon><
|
|
4
|
+
<div class="m-fields-group-list-item-header">
|
|
5
|
+
<TMagicButton link :disabled="disabled" @click="expandHandler" class="expand-button">
|
|
6
|
+
<TMagicIcon><ArrowDown v-if="expand" /><ArrowRight v-else /></TMagicIcon>
|
|
7
7
|
</TMagicButton>
|
|
8
8
|
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
<span v-html="title"></span>
|
|
10
|
+
<TMagicTooltip :content="`删除 ${title}`">
|
|
11
|
+
<TMagicButton
|
|
12
|
+
v-if="!isCompare"
|
|
13
|
+
v-show="showDelete"
|
|
14
|
+
size="default"
|
|
15
|
+
link
|
|
16
|
+
class="delete-button"
|
|
17
|
+
:icon="Delete"
|
|
18
|
+
:disabled="disabled"
|
|
19
|
+
@click="removeHandler"
|
|
20
|
+
></TMagicButton>
|
|
21
|
+
</TMagicTooltip>
|
|
19
22
|
|
|
20
23
|
<TMagicButton
|
|
21
24
|
v-if="copyable && !isCompare"
|
|
22
25
|
link
|
|
23
|
-
size="
|
|
26
|
+
size="default"
|
|
24
27
|
type="primary"
|
|
25
28
|
:icon="DocumentCopy"
|
|
26
29
|
:disabled="disabled"
|
|
@@ -32,18 +35,18 @@
|
|
|
32
35
|
<TMagicButton
|
|
33
36
|
v-show="index !== 0"
|
|
34
37
|
link
|
|
35
|
-
size="
|
|
38
|
+
size="default"
|
|
36
39
|
:disabled="disabled"
|
|
37
|
-
:icon="
|
|
40
|
+
:icon="Top"
|
|
38
41
|
@click="changeOrder(-1)"
|
|
39
42
|
>上移</TMagicButton
|
|
40
43
|
>
|
|
41
44
|
<TMagicButton
|
|
42
45
|
v-show="index !== length - 1"
|
|
43
46
|
link
|
|
44
|
-
size="
|
|
47
|
+
size="default"
|
|
45
48
|
:disabled="disabled"
|
|
46
|
-
:icon="
|
|
49
|
+
:icon="Bottom"
|
|
47
50
|
@click="changeOrder(1)"
|
|
48
51
|
>下移</TMagicButton
|
|
49
52
|
>
|
|
@@ -107,9 +110,9 @@
|
|
|
107
110
|
|
|
108
111
|
<script setup lang="ts">
|
|
109
112
|
import { computed, inject, ref } from 'vue';
|
|
110
|
-
import {
|
|
113
|
+
import { ArrowDown, ArrowRight, Bottom, Delete, DocumentCopy, Position, Top } from '@element-plus/icons-vue';
|
|
111
114
|
|
|
112
|
-
import { TMagicButton, TMagicCard, TMagicIcon, TMagicInputNumber, TMagicPopover } from '@tmagic/design';
|
|
115
|
+
import { TMagicButton, TMagicCard, TMagicIcon, TMagicInputNumber, TMagicPopover, TMagicTooltip } from '@tmagic/design';
|
|
113
116
|
|
|
114
117
|
import type { ContainerChangeEventData, FormState, GroupListConfig } from '../schema';
|
|
115
118
|
import { filterFunction } from '../utils/form';
|
|
@@ -152,7 +155,10 @@ const rowConfig = computed(() => ({
|
|
|
152
155
|
|
|
153
156
|
const title = computed(() => {
|
|
154
157
|
if (props.config.titleKey && props.model[props.config.titleKey]) {
|
|
155
|
-
|
|
158
|
+
const { titlePrefix } = props.config;
|
|
159
|
+
return titlePrefix
|
|
160
|
+
? `${titlePrefix} ${String(props.index + 1)}: ${props.model[props.config.titleKey]}`
|
|
161
|
+
: `${props.model[props.config.titleKey]}`;
|
|
156
162
|
}
|
|
157
163
|
|
|
158
164
|
if (props.config.title) {
|
package/src/containers/Panel.vue
CHANGED
|
@@ -3,10 +3,17 @@
|
|
|
3
3
|
v-if="items && items.length"
|
|
4
4
|
class="box-card m-form-panel"
|
|
5
5
|
:body-style="{ display: expand ? 'block' : 'none' }"
|
|
6
|
+
:flat="config.flat"
|
|
6
7
|
>
|
|
7
8
|
<template #header>
|
|
8
9
|
<div style="width: 100%; display: flex; align-items: center">
|
|
9
|
-
<TMagicButton
|
|
10
|
+
<TMagicButton
|
|
11
|
+
style="padding: 0; margin-right: 10px"
|
|
12
|
+
link
|
|
13
|
+
:icon="expand ? ArrowDown : ArrowRight"
|
|
14
|
+
@click="expand = !expand"
|
|
15
|
+
v-if="!hideExpand"
|
|
16
|
+
>
|
|
10
17
|
</TMagicButton>
|
|
11
18
|
<slot name="header">
|
|
12
19
|
<span style="cursor: pointer" @click="expand = !expand">{{ filter(config.title) }}</span>
|
|
@@ -62,7 +69,7 @@
|
|
|
62
69
|
|
|
63
70
|
<script setup lang="ts">
|
|
64
71
|
import { computed, inject, ref } from 'vue';
|
|
65
|
-
import {
|
|
72
|
+
import { ArrowDown, ArrowRight } from '@element-plus/icons-vue';
|
|
66
73
|
|
|
67
74
|
import { TMagicButton, TMagicCard } from '@tmagic/design';
|
|
68
75
|
|
|
@@ -85,6 +92,7 @@ const props = defineProps<{
|
|
|
85
92
|
prop?: string;
|
|
86
93
|
size?: string;
|
|
87
94
|
disabled?: boolean;
|
|
95
|
+
hideExpand?: boolean;
|
|
88
96
|
}>();
|
|
89
97
|
|
|
90
98
|
const emit = defineEmits<{
|
|
@@ -107,7 +115,6 @@ const onAddDiffCount = () => emit('addDiffCount');
|
|
|
107
115
|
|
|
108
116
|
defineExpose({
|
|
109
117
|
getExpand: () => expand.value,
|
|
110
|
-
|
|
111
118
|
setExpand: (v: boolean) => {
|
|
112
119
|
expand.value = v;
|
|
113
120
|
},
|
|
@@ -9,15 +9,18 @@
|
|
|
9
9
|
>
|
|
10
10
|
</TMagicButton>
|
|
11
11
|
</TMagicTooltip>
|
|
12
|
+
|
|
12
13
|
<TMagicButton
|
|
13
14
|
v-show="showDelete(index + 1 + currentPage * pageSize - 1)"
|
|
14
15
|
size="small"
|
|
15
16
|
type="danger"
|
|
16
17
|
link
|
|
17
18
|
title="删除"
|
|
18
|
-
:icon="config.deleteActionButtonIcon || Delete"
|
|
19
|
+
:icon="flat ? undefined : config.deleteActionButtonIcon || Delete"
|
|
19
20
|
@click="removeHandler(index + 1 + currentPage * pageSize - 1)"
|
|
20
|
-
|
|
21
|
+
>
|
|
22
|
+
<template v-if="flat">删除</template>
|
|
23
|
+
</TMagicButton>
|
|
21
24
|
|
|
22
25
|
<TMagicButton
|
|
23
26
|
v-if="copyable(index + 1 + currentPage * pageSize - 1)"
|
|
@@ -25,10 +28,12 @@
|
|
|
25
28
|
size="small"
|
|
26
29
|
type="primary"
|
|
27
30
|
title="复制"
|
|
28
|
-
:icon="config.copyActionButtonIcon || DocumentCopy"
|
|
31
|
+
:icon="flat ? undefined : config.copyActionButtonIcon || DocumentCopy"
|
|
29
32
|
:disabled="disabled"
|
|
30
33
|
@click="copyHandler(index + 1 + currentPage * pageSize - 1)"
|
|
31
|
-
|
|
34
|
+
>
|
|
35
|
+
<template v-if="flat">复制</template>
|
|
36
|
+
</TMagicButton>
|
|
32
37
|
</template>
|
|
33
38
|
|
|
34
39
|
<script setup lang="ts">
|
|
@@ -53,6 +58,7 @@ const props = defineProps<{
|
|
|
53
58
|
row: any;
|
|
54
59
|
prop?: string;
|
|
55
60
|
sortKey?: string;
|
|
61
|
+
flat?: boolean;
|
|
56
62
|
}>();
|
|
57
63
|
|
|
58
64
|
const mForm = inject<FormState | undefined>('mForm');
|
|
@@ -6,6 +6,7 @@ import { type TableColumnOptions, TMagicIcon, TMagicTooltip } from '@tmagic/desi
|
|
|
6
6
|
import type { FormItemConfig, FormState, TableColumnConfig } from '@tmagic/form-schema';
|
|
7
7
|
|
|
8
8
|
import type { ContainerChangeEventData } from '../../schema';
|
|
9
|
+
import { isGlobalFlat } from '../../utils/config';
|
|
9
10
|
import { display as displayFunc, getDataByPage, sortArray } from '../../utils/form';
|
|
10
11
|
import Container from '../Container.vue';
|
|
11
12
|
|
|
@@ -111,23 +112,26 @@ export const useTableColumns = (
|
|
|
111
112
|
},
|
|
112
113
|
});
|
|
113
114
|
}
|
|
114
|
-
|
|
115
|
-
let actionFixed: 'left' | 'right' | undefined = props.config.fixed === false ? undefined :
|
|
116
|
-
|
|
115
|
+
const defaultFixed: 'left' | 'right' = isGlobalFlat.value ? 'right' : 'left';
|
|
116
|
+
let actionFixed: 'left' | 'right' | undefined = props.config.fixed === false ? undefined : defaultFixed;
|
|
117
117
|
if (typeof props.config.fixed === 'string' && ['left', 'right'].includes(props.config.fixed)) {
|
|
118
118
|
actionFixed = props.config.fixed;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
const actionFlat = props.config.flat === undefined && isGlobalFlat.value ? true : props.config.flat;
|
|
122
|
+
|
|
121
123
|
const actionColumn = {
|
|
122
124
|
props: {
|
|
123
125
|
label: '操作',
|
|
124
126
|
fixed: actionFixed,
|
|
127
|
+
|
|
125
128
|
width: props.config.operateColWidth ?? (props.config.dropSortHandle && props.config.dropSort ? 132 : 112),
|
|
126
129
|
align: 'center',
|
|
127
130
|
},
|
|
128
131
|
cell: ({ row, $index }: any) =>
|
|
129
132
|
h(ActionsColumn, {
|
|
130
133
|
row,
|
|
134
|
+
flat: actionFlat,
|
|
131
135
|
index: $index,
|
|
132
136
|
model: props.model,
|
|
133
137
|
config: props.config,
|
|
@@ -37,11 +37,17 @@
|
|
|
37
37
|
:size="addButtonSize"
|
|
38
38
|
:plain="displayMode === 'table'"
|
|
39
39
|
:icon="Plus"
|
|
40
|
+
text
|
|
40
41
|
:disabled="disabled"
|
|
41
42
|
v-bind="currentConfig.addButtonConfig?.props || { type: 'primary' }"
|
|
42
43
|
@click="newHandler"
|
|
43
44
|
>
|
|
44
|
-
{{
|
|
45
|
+
{{
|
|
46
|
+
currentConfig.addButtonConfig?.text ||
|
|
47
|
+
(displayMode === 'table'
|
|
48
|
+
? `新增一行${groupListConfig.titlePrefix || ''}`
|
|
49
|
+
: `新增${groupListConfig.titlePrefix || ''}`)
|
|
50
|
+
}}
|
|
45
51
|
</TMagicButton>
|
|
46
52
|
</template>
|
|
47
53
|
</component>
|