@tmagic/form 1.8.0-beta.8 → 1.8.0-manmanyu.9

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 (59) hide show
  1. package/dist/es/Form.vue_vue_type_script_setup_true_lang.js +44 -5
  2. package/dist/es/FormDialog.vue_vue_type_script_setup_true_lang.js +12 -5
  3. package/dist/es/FormDrawer.vue_vue_type_script_setup_true_lang.js +13 -5
  4. package/dist/es/containers/Container.vue_vue_type_script_setup_true_lang.js +20 -15
  5. package/dist/es/containers/GroupListItem.vue_vue_type_script_setup_true_lang.js +22 -18
  6. package/dist/es/containers/Panel.vue_vue_type_script_setup_true_lang.js +16 -10
  7. package/dist/es/containers/table/ActionsColumn.vue_vue_type_script_setup_true_lang.js +13 -6
  8. package/dist/es/containers/table/useTableColumns.js +1 -0
  9. package/dist/es/containers/table-group-list/TableGroupList.vue_vue_type_script_setup_true_lang.js +2 -1
  10. package/dist/es/fields/Cascader.vue_vue_type_script_setup_true_lang.js +4 -1
  11. package/dist/es/fields/Checkbox.vue_vue_type_script_setup_true_lang.js +4 -1
  12. package/dist/es/fields/CheckboxGroup.vue_vue_type_script_setup_true_lang.js +4 -1
  13. package/dist/es/fields/ColorPicker.vue_vue_type_script_setup_true_lang.js +4 -1
  14. package/dist/es/fields/Date.vue_vue_type_script_setup_true_lang.js +4 -1
  15. package/dist/es/fields/DateTime.vue_vue_type_script_setup_true_lang.js +4 -1
  16. package/dist/es/fields/Daterange.vue_vue_type_script_setup_true_lang.js +4 -1
  17. package/dist/es/fields/Display.vue_vue_type_script_setup_true_lang.js +4 -1
  18. package/dist/es/fields/DynamicField.vue_vue_type_script_setup_true_lang.js +4 -1
  19. package/dist/es/fields/Link.vue_vue_type_script_setup_true_lang.js +29 -7
  20. package/dist/es/fields/Number.vue_vue_type_script_setup_true_lang.js +4 -1
  21. package/dist/es/fields/NumberRange.vue_vue_type_script_setup_true_lang.js +4 -1
  22. package/dist/es/fields/RadioGroup.vue_vue_type_script_setup_true_lang.js +16 -8
  23. package/dist/es/fields/Select.vue_vue_type_script_setup_true_lang.js +4 -1
  24. package/dist/es/fields/Switch.vue_vue_type_script_setup_true_lang.js +4 -1
  25. package/dist/es/fields/Text.vue_vue_type_script_setup_true_lang.js +112 -77
  26. package/dist/es/fields/Textarea.vue_vue_type_script_setup_true_lang.js +4 -1
  27. package/dist/es/fields/Time.vue_vue_type_script_setup_true_lang.js +4 -1
  28. package/dist/es/fields/Timerange.vue_vue_type_script_setup_true_lang.js +4 -1
  29. package/dist/es/plugin.js +2 -0
  30. package/dist/es/style.css +120 -8
  31. package/dist/style.css +120 -8
  32. package/dist/themes/magic-admin.css +53 -0
  33. package/dist/tmagic-form.umd.cjs +392 -201
  34. package/package.json +4 -4
  35. package/src/Form.vue +53 -4
  36. package/src/FormDialog.vue +14 -3
  37. package/src/FormDrawer.vue +15 -4
  38. package/src/containers/Container.vue +14 -5
  39. package/src/containers/GroupListItem.vue +14 -12
  40. package/src/containers/Panel.vue +10 -3
  41. package/src/containers/table/ActionsColumn.vue +10 -4
  42. package/src/containers/table/useTableColumns.ts +1 -0
  43. package/src/containers/table-group-list/TableGroupList.vue +5 -1
  44. package/src/fields/Link.vue +17 -3
  45. package/src/fields/RadioGroup.vue +11 -5
  46. package/src/fields/Text.vue +43 -19
  47. package/src/plugin.ts +2 -0
  48. package/src/theme/container.scss +3 -0
  49. package/src/theme/fieldset.scss +50 -0
  50. package/src/theme/form.scss +6 -0
  51. package/src/theme/group-list.scss +8 -7
  52. package/src/theme/index.scss +1 -0
  53. package/src/theme/link.scss +17 -0
  54. package/src/theme/panel.scss +1 -1
  55. package/src/theme/radio-group.scss +23 -0
  56. package/src/theme/tabs.scss +2 -2
  57. package/src/theme/text.scss +38 -0
  58. package/src/theme/themes/magic-admin/index.scss +89 -0
  59. package/types/index.d.ts +43 -1
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.8.0-beta.8",
2
+ "version": "1.8.0-manmanyu.9",
3
3
  "name": "@tmagic/form",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -52,9 +52,9 @@
52
52
  "peerDependencies": {
53
53
  "vue": "^3.5.34",
54
54
  "typescript": "^6.0.3",
55
- "@tmagic/design": "1.8.0-beta.8",
56
- "@tmagic/utils": "1.8.0-beta.8",
57
- "@tmagic/form-schema": "1.8.0-beta.8"
55
+ "@tmagic/design": "1.8.0-manmanyu.9",
56
+ "@tmagic/utils": "1.8.0-manmanyu.9",
57
+ "@tmagic/form-schema": "1.8.0-manmanyu.9"
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="m-form"
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,10 +36,10 @@
32
36
  </template>
33
37
 
34
38
  <script setup lang="ts">
35
- import { provide, reactive, ref, shallowRef, toRaw, useTemplateRef, watch, watchEffect } from 'vue';
39
+ import { computed, inject, provide, reactive, ref, shallowRef, toRaw, useTemplateRef, watch, watchEffect } from 'vue';
36
40
  import { cloneDeep, isEqual } from 'lodash-es';
37
41
 
38
- import { TMagicForm, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
42
+ import { M_THEME_KEY, TMagicForm, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
39
43
  import { setValueByKeyPath } from '@tmagic/utils';
40
44
 
41
45
  import Container from './containers/Container.vue';
@@ -107,6 +111,15 @@ const props = withDefaults(
107
111
  * 通过 provide 下发,对整棵表单的所有层级 Container 生效,只需在 MForm 这一层传一次。
108
112
  */
109
113
  selfDiffFieldTypes?: string[] | ((_defaultTypes: string[]) => string[]);
114
+ /**
115
+ * 主题名称:对应 `packages/form/src/theme/themes/<theme>/index.scss` 的目录名。
116
+ *
117
+ * 设置后会在表单根元素上追加 `m-form--<theme>` 修饰类,配合按需引入
118
+ * `@tmagic/form/dist/themes/<theme>.css` 即可启用主题样式。
119
+ *
120
+ * 例如:`<MForm theme="magic-admin" />` + `import '@tmagic/form/dist/themes/magic-admin.css'`。
121
+ */
122
+ theme?: string;
110
123
  }>(),
111
124
  {
112
125
  config: () => [],
@@ -134,6 +147,27 @@ const fields = new Map<string, any>();
134
147
 
135
148
  const requestFuc = getConfig('request') as Function;
136
149
 
150
+ /**
151
+ * 当前表单生效的主题名称:
152
+ * - 优先用本组件自己的 `props.theme`;
153
+ * - 没设置时回退到最近祖先 `<MEditor>` / `<MForm>` provide 的主题,便于内嵌于编辑器
154
+ * 时自动跟随外层主题,无需在每个 `MForm` 上重复传 `theme`。
155
+ *
156
+ * 同时把合并后的值再 provide 出去(见下方 `provide(M_THEME_KEY, ...)`),让 form 子树
157
+ * 里再嵌套的 portal 组件(`TMagicPopover` 等)依然能拿到非空主题。
158
+ */
159
+ const ancestorTheme = inject(M_THEME_KEY, null);
160
+ const effectiveTheme = computed(() => props.theme || ancestorTheme?.value || '');
161
+
162
+ /**
163
+ * 拼到 `formState.popperClass` 上的主题修饰类(仅 `m-theme--<theme>`,
164
+ * 不带 `m-form` / `m-editor` 前缀,因为 Element Plus 弹层节点本身既不是 form 也不是 editor)。
165
+ *
166
+ * 这条类会随所有读 `mForm.popperClass` 的字段(Select / DateTime / Cascader 等)下发到
167
+ * Element Plus 的 `popper-class`,让 portal 节点也命中 `m-theme--<theme>` 上的 CSS 变量。
168
+ */
169
+ const themeClass = computed(() => (effectiveTheme.value ? `m-theme--${effectiveTheme.value}` : ''));
170
+
137
171
  /**
138
172
  * formState 实现说明:
139
173
  *
@@ -150,13 +184,21 @@ const requestFuc = getConfig('request') as Function;
150
184
  * 把最新值刷进 formState。
151
185
  * - accessor 描述符(`{ get stage() { return ... } }`)按原样写入,调用方可以控制
152
186
  * 读时求值,每次读取都会重新执行 getter。
187
+ *
188
+ * 4. `popperClass` 会自动拼接 `themeClass`:调用方传入的 `popperClass` + 当前主题
189
+ * 修饰类(含祖先 `<MEditor>` provide 的主题)。这样所有透传到 Element Plus 弹层
190
+ * `popper-class` 的字段(Select / DateTime / Cascader 等)能自带主题作用域。
153
191
  */
154
192
  const formState: FormState = reactive<FormState>({
155
193
  get keyProp() {
156
194
  return props.keyProp;
157
195
  },
158
196
  get popperClass() {
159
- return props.popperClass;
197
+ const userClass = props.popperClass ?? '';
198
+ const tc = themeClass.value;
199
+ if (!userClass) return tc;
200
+ if (!tc) return userClass;
201
+ return `${userClass} ${tc}`;
160
202
  },
161
203
  get config() {
162
204
  return props.config;
@@ -243,6 +285,13 @@ watchEffect(async (onCleanup) => {
243
285
 
244
286
  provide('mForm', formState);
245
287
 
288
+ /**
289
+ * 把生效主题(自身或祖先)再 provide 出去,供 form 子树内含 `Teleport` 的组件
290
+ * (如 `TMagicPopover`)在传送目标上挂 `m-theme--<theme>` 类。
291
+ * 详见 `@tmagic/design/theme.ts`。
292
+ */
293
+ provide(M_THEME_KEY, effectiveTheme);
294
+
246
295
  // 对比相关配置单独通过 provide 下发,所有层级的 Container 通过 inject 获取,无需逐层透传 prop。
247
296
  // 用 getter 对象保证读取时回到最新的 props 值,维持响应式。
248
297
  provide(FORM_DIFF_CONFIG_KEY, {
@@ -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"
@@ -32,6 +32,7 @@
32
32
  :inline="inline"
33
33
  :prevent-submit-default="preventSubmitDefault"
34
34
  :extend-state="extendState"
35
+ :theme="effectiveTheme"
35
36
  @change="changeHandler"
36
37
  ></Form>
37
38
  <slot></slot>
@@ -64,9 +65,9 @@
64
65
  </template>
65
66
 
66
67
  <script setup lang="ts">
67
- import { computed, ref } from 'vue';
68
+ import { computed, inject, provide, ref } from 'vue';
68
69
 
69
- import { TMagicButton, TMagicCol, TMagicDialog, TMagicRow } from '@tmagic/design';
70
+ import { M_THEME_KEY, TMagicButton, TMagicCol, TMagicDialog, TMagicRow } from '@tmagic/design';
70
71
 
71
72
  import Form from './Form.vue';
72
73
  import { ContainerChangeEventData, FormConfig, FormState, FormValue, StepConfig } from './schema';
@@ -98,6 +99,12 @@ const props = withDefaults(
98
99
  showCancel?: boolean;
99
100
  /** 透传给内部 `MForm`,用于扩展 `formState`(如注入 `$message` / `$store` 等) */
100
101
  extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
102
+ /**
103
+ * 主题名。优先级:传入 `theme` prop > 祖先 `provide(M_THEME_KEY)` > 空串。
104
+ * 计算结果会再次 `provide` 出去,使得 Dialog 被 Teleport 到 body 后,内部子树
105
+ * (包括 `MForm` 以及更深的 popover / dropdown)仍能拿到主题。
106
+ */
107
+ theme?: string;
101
108
  }>(),
102
109
  {
103
110
  config: () => [],
@@ -111,6 +118,10 @@ const props = withDefaults(
111
118
  },
112
119
  );
113
120
 
121
+ const ancestorTheme = inject(M_THEME_KEY, null);
122
+ const effectiveTheme = computed(() => props.theme || ancestorTheme?.value || '');
123
+ provide(M_THEME_KEY, effectiveTheme);
124
+
114
125
  const emit = defineEmits(['close', 'submit', 'error', 'change']);
115
126
 
116
127
  const form = ref<InstanceType<typeof Form>>();
@@ -1,6 +1,6 @@
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
5
  v-model="visible"
6
6
  :title="title"
@@ -29,6 +29,7 @@
29
29
  :inline="inline"
30
30
  :prevent-submit-default="preventSubmitDefault"
31
31
  :extend-state="extendState"
32
+ :theme="effectiveTheme"
32
33
  @change="changeHandler"
33
34
  ></Form>
34
35
  <slot></slot>
@@ -55,9 +56,9 @@
55
56
  </template>
56
57
 
57
58
  <script setup lang="ts">
58
- import { ref, watchEffect } from 'vue';
59
+ import { computed, inject, provide, ref, watchEffect } from 'vue';
59
60
 
60
- import { TMagicButton, TMagicCol, TMagicDrawer, TMagicRow } from '@tmagic/design';
61
+ import { M_THEME_KEY, TMagicButton, TMagicCol, TMagicDrawer, TMagicRow } from '@tmagic/design';
61
62
 
62
63
  import Form from './Form.vue';
63
64
  import type { ContainerChangeEventData, FormConfig, FormState, FormValue } from './schema';
@@ -66,7 +67,7 @@ defineOptions({
66
67
  name: 'MFormDialog',
67
68
  });
68
69
 
69
- withDefaults(
70
+ const props = withDefaults(
70
71
  defineProps<{
71
72
  config?: FormConfig;
72
73
  values?: Object;
@@ -86,6 +87,12 @@ withDefaults(
86
87
  beforeClose?: (_done: (_cancel?: boolean) => void) => void;
87
88
  /** 透传给内部 `MForm`,用于扩展 `formState`(如注入 `$message` / `$store` 等) */
88
89
  extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
90
+ /**
91
+ * 主题名。优先级:传入 `theme` prop > 祖先 `provide(M_THEME_KEY)` > 空串。
92
+ * 计算结果会再次 `provide` 出去,使得 Drawer 被 Teleport 到 body 后,内部子树
93
+ * (包括 `MForm` 以及更深的 popover / dropdown)仍能拿到主题。
94
+ */
95
+ theme?: string;
89
96
  }>(),
90
97
  {
91
98
  closeOnPressEscape: true,
@@ -95,6 +102,10 @@ withDefaults(
95
102
  },
96
103
  );
97
104
 
105
+ const ancestorTheme = inject(M_THEME_KEY, null);
106
+ const effectiveTheme = computed(() => props.theme || ancestorTheme?.value || '');
107
+ provide(M_THEME_KEY, effectiveTheme);
108
+
98
109
  const emit = defineEmits(['close', 'closed', 'submit', 'error', 'change', 'open', 'opened']);
99
110
 
100
111
  const drawer = ref<InstanceType<typeof TMagicDrawer>>();
@@ -33,6 +33,9 @@
33
33
  :label-title="config.labelTitle"
34
34
  :text="text"
35
35
  ></FormLabel>
36
+ <span class="m-form-tip m-form-title-extra" v-if="config.titleExtra && config.labelPosition === 'top'">
37
+ {{ config.titleExtra }}</span
38
+ >
36
39
  </slot>
37
40
  </template>
38
41
 
@@ -220,17 +223,23 @@
220
223
  </template>
221
224
  </template>
222
225
 
223
- <div style="text-align: center" v-if="config.expand && type !== 'fieldset'">
224
- <TMagicButton type="primary" size="small" :disabled="false" link @click="expandHandler">{{
225
- expand ? '收起配置' : '展开更多配置'
226
- }}</TMagicButton>
226
+ <div class="m-form-container-expand" v-if="config.expand && type !== 'fieldset'">
227
+ <TMagicButton
228
+ type="primary"
229
+ size="small"
230
+ :disabled="false"
231
+ link
232
+ @click="expandHandler"
233
+ :icon="expand ? ArrowUp : ArrowDown"
234
+ >{{ expand ? '收起配置' : '展开更多配置' }}</TMagicButton
235
+ >
227
236
  </div>
228
237
  </div>
229
238
  </template>
230
239
 
231
240
  <script setup lang="ts">
232
241
  import { computed, inject, readonly, ref, toRaw, watch, watchEffect } from 'vue';
233
- import { WarningFilled } from '@element-plus/icons-vue';
242
+ import { ArrowDown, ArrowUp, WarningFilled } from '@element-plus/icons-vue';
234
243
  import { isEqual } from 'lodash-es';
235
244
 
236
245
  import { TMagicButton, TMagicFormItem, TMagicIcon, TMagicTooltip } from '@tmagic/design';
@@ -1,17 +1,19 @@
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><CaretBottom v-if="expand" /><CaretRight v-else /></TMagicIcon><span v-html="title"></span>
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
+ <span v-html="title"></span>
10
+
9
11
  <TMagicButton
10
12
  v-if="!isCompare"
11
13
  v-show="showDelete"
12
- type="danger"
13
- size="small"
14
+ size="default"
14
15
  link
16
+ class="delete-button"
15
17
  :icon="Delete"
16
18
  :disabled="disabled"
17
19
  @click="removeHandler"
@@ -20,7 +22,7 @@
20
22
  <TMagicButton
21
23
  v-if="copyable && !isCompare"
22
24
  link
23
- size="small"
25
+ size="default"
24
26
  type="primary"
25
27
  :icon="DocumentCopy"
26
28
  :disabled="disabled"
@@ -32,18 +34,18 @@
32
34
  <TMagicButton
33
35
  v-show="index !== 0"
34
36
  link
35
- size="small"
37
+ size="default"
36
38
  :disabled="disabled"
37
- :icon="CaretTop"
39
+ :icon="Top"
38
40
  @click="changeOrder(-1)"
39
41
  >上移</TMagicButton
40
42
  >
41
43
  <TMagicButton
42
44
  v-show="index !== length - 1"
43
45
  link
44
- size="small"
46
+ size="default"
45
47
  :disabled="disabled"
46
- :icon="CaretBottom"
48
+ :icon="Bottom"
47
49
  @click="changeOrder(1)"
48
50
  >下移</TMagicButton
49
51
  >
@@ -107,7 +109,7 @@
107
109
 
108
110
  <script setup lang="ts">
109
111
  import { computed, inject, ref } from 'vue';
110
- import { CaretBottom, CaretRight, CaretTop, Delete, DocumentCopy, Position } from '@element-plus/icons-vue';
112
+ import { ArrowDown, ArrowRight, Bottom, Delete, DocumentCopy, Position, Top } from '@element-plus/icons-vue';
111
113
 
112
114
  import { TMagicButton, TMagicCard, TMagicIcon, TMagicInputNumber, TMagicPopover } from '@tmagic/design';
113
115
 
@@ -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 style="padding: 0" link :icon="expand ? CaretBottom : CaretRight" @click="expand = !expand">
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 { CaretBottom, CaretRight } from '@element-plus/icons-vue';
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
- ></TMagicButton>
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
- ></TMagicButton>
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');
@@ -128,6 +128,7 @@ export const useTableColumns = (
128
128
  cell: ({ row, $index }: any) =>
129
129
  h(ActionsColumn, {
130
130
  row,
131
+ flat: props.config.flat,
131
132
  index: $index,
132
133
  model: props.model,
133
134
  config: props.config,
@@ -37,11 +37,15 @@
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
- {{ currentConfig.addButtonConfig?.text || (displayMode === 'table' ? '新增一行' : '新增') }}
45
+ {{
46
+ currentConfig.addButtonConfig?.text ||
47
+ (displayMode === 'table' ? '新增一行' : `新增${groupListConfig.titlePrefix || ''}`)
48
+ }}
45
49
  </TMagicButton>
46
50
  </template>
47
51
  </component>
@@ -1,5 +1,16 @@
1
1
  <template>
2
- <a v-if="config.href && !disabled" target="_blank" :href="href" :style="config.css || {}">{{ displayText }}</a>
2
+ <a
3
+ target="_blank"
4
+ :href="href"
5
+ v-if="displayTheme === 'magic-admin' && config.href && !disabled"
6
+ class="magic-admin-link"
7
+ :style="config.css || {}"
8
+ >
9
+ <TMagicButton link type="primary">
10
+ <TMagicIcon><Notebook /></TMagicIcon>{{ displayText }}
11
+ </TMagicButton>
12
+ </a>
13
+ <a v-else-if="config.href && !disabled" target="_blank" :href="href" :style="config.css || {}">{{ displayText }}</a>
3
14
  <span v-else-if="config.href && disabled" :style="config.disabledCss || {}">{{ displayText }}</span>
4
15
  <div v-else class="m-fields-link">
5
16
  <TMagicButton link type="primary" @click="editHandler">点击编辑</TMagicButton>
@@ -18,8 +29,9 @@
18
29
 
19
30
  <script lang="ts" setup>
20
31
  import { computed, inject, readonly, ref } from 'vue';
32
+ import { Notebook } from '@element-plus/icons-vue';
21
33
 
22
- import { TMagicButton } from '@tmagic/design';
34
+ import { TMagicButton, TMagicIcon, useTheme } from '@tmagic/design';
23
35
 
24
36
  import FormDialog from '../FormDialog.vue';
25
37
  import type { FieldProps, FormState, LinkConfig } from '../schema';
@@ -29,10 +41,12 @@ defineOptions({
29
41
  name: 'MFormLink',
30
42
  });
31
43
 
32
- const props = defineProps<FieldProps<LinkConfig>>();
44
+ const props = defineProps<FieldProps<LinkConfig> & { theme?: string }>();
33
45
 
34
46
  const emit = defineEmits(['change']);
35
47
 
48
+ const displayTheme = useTheme(props);
49
+
36
50
  useAddField(props.prop);
37
51
 
38
52
  const formValue = ref({});
@@ -8,9 +8,14 @@
8
8
  @click="clickHandler(option.value)"
9
9
  >
10
10
  <TMagicTooltip :disabled="!Boolean(option.tooltip)" placement="top-start" :content="option.tooltip">
11
- <div>
12
- <TMagicIcon v-if="option.icon" :size="iconSize"><component :is="option.icon"></component></TMagicIcon>
13
- <span v-if="option.text">{{ option.text }}</span>
11
+ <div class="m-fields-radio-group__option">
12
+ <TMagicIcon
13
+ v-if="option.icon"
14
+ :size="iconSize"
15
+ :class="{ 'm-fields-radio-group__icon_with_text': !!option.text }"
16
+ ><component :is="option.icon"></component
17
+ ></TMagicIcon>
18
+ <span v-if="option.text" class="m-fields-radio-group__text">{{ option.text }}</span>
14
19
  </div>
15
20
  </TMagicTooltip>
16
21
  </component>
@@ -42,13 +47,14 @@ const clickHandler = (item: string | number | boolean) => {
42
47
 
43
48
  useAddField(props.prop);
44
49
 
50
+ // 这里换了设计稿里的图标,所以需要调整一下图标大小
45
51
  const iconSize = computed(() => {
46
52
  if (props.size === 'small') {
47
- return '12';
53
+ return '14';
48
54
  }
49
55
  if (props.size === 'large') {
50
56
  return '16';
51
57
  }
52
- return '14';
58
+ return '16';
53
59
  });
54
60
  </script>
@@ -1,6 +1,31 @@
1
1
  <template>
2
- <div class="m-fields-text">
2
+ <div :class="['m-fields-text', { 'm-fields-text--static': config.static }]">
3
+ <div v-if="config.disabled"></div>
4
+ <!-- 新增静态展示文本样式 -->
5
+ <template v-if="config.static">
6
+ <span v-if="config.prepend" class="m-fields-text__prepend">{{ config.prepend }}</span>
7
+ <span class="m-fields-text__value">{{ value }}</span>
8
+ <template v-if="appendConfig">
9
+ <TMagicButton
10
+ v-if="appendConfig.type === 'button'"
11
+ style="color: #0056ea"
12
+ :size="size"
13
+ @click.prevent="buttonClickHandler"
14
+ >
15
+ {{ appendConfig.text }}
16
+ </TMagicButton>
17
+ <img
18
+ v-else-if="appendConfig.type === 'icon'"
19
+ class="m-fields-text__icon"
20
+ :src="appendConfig.text"
21
+ @click="buttonClickHandler"
22
+ />
23
+ <span v-else>{{ appendConfig.text }}</span>
24
+ </template>
25
+ </template>
26
+
3
27
  <TMagicInput
28
+ v-else
4
29
  v-model="value"
5
30
  ref="input"
6
31
  :clearable="config.clearable ?? true"
@@ -17,17 +42,18 @@
17
42
  <template #append v-if="appendConfig">
18
43
  <TMagicButton
19
44
  v-if="appendConfig.type === 'button'"
20
- style="color: #409eff"
45
+ style="color: #0056ea"
21
46
  :size="size"
22
47
  @click.prevent="buttonClickHandler"
23
48
  >
24
49
  {{ appendConfig.text }}
25
50
  </TMagicButton>
51
+ <img v-else-if="appendConfig.type === 'icon'" :src="appendConfig.text" @click="buttonClickHandler" />
26
52
  <span v-else>{{ appendConfig.text }}</span>
27
53
  </template>
28
54
  </TMagicInput>
29
55
 
30
- <Teleport to="body">
56
+ <Teleport to="body" v-if="!config.static">
31
57
  <div v-if="popoverVisible" class="tmagic-form-text-popper m-form-item__content" ref="popoverEl">
32
58
  <div class="m-form-validate__warning">输入内容前后有空格,是否移除空格?</div>
33
59
  <div style="display: flex; justify-content: flex-end">
@@ -80,28 +106,26 @@ watch(
80
106
  );
81
107
 
82
108
  const appendConfig = computed(() => {
83
- if (typeof props.config.append === 'string') {
109
+ const { append } = props.config;
110
+
111
+ // 字符串形态:纯文本 append。
112
+ if (typeof append === 'string') {
84
113
  return {
85
114
  type: 'text',
86
- text: props.config.append,
115
+ text: append,
87
116
  handler: undefined,
88
117
  };
89
118
  }
90
- if (typeof props.config.append === 'object') {
91
- if (typeof props.config.append?.handler === 'function') {
92
- return {
93
- type: 'button',
94
- text: props.config.append.text,
95
- handler: props.config.append.handler,
96
- };
97
- }
98
- if (props.config.append) {
99
- if (props.config.append.value === 0) {
100
- return false;
101
- }
102
119
 
103
- return props.config.append;
104
- }
120
+ // 对象形态:按 schema 定义,`type` 可为 `'button' | 'icon'`,`handler` 可选。
121
+ //
122
+ // 旧逻辑里只要带 handler 就强制覆盖为 `type: 'button'`,导致 schema 中显式传入的
123
+ // `type: 'icon'` 在到达模板前被抹掉(参见 `@editor/utils/props.ts` 中 ID 字段
124
+ // 的复制按钮配置)。这里直接返回原对象,模板按 `type` 分支渲染 button / icon / text。
125
+ if (typeof append === 'object' && append) {
126
+ // `value === 0` 沿用旧约定:作为「隐藏 append」的开关。
127
+ if (append.value === 0) return false;
128
+ return append;
105
129
  }
106
130
 
107
131
  return false;
package/src/plugin.ts CHANGED
@@ -49,6 +49,7 @@ import Timerange from './fields/Timerange.vue';
49
49
  import { setConfig } from './utils/config';
50
50
  import Form from './Form.vue';
51
51
  import FormDialog from './FormDialog.vue';
52
+ import FormDrawer from './FormDrawer.vue';
52
53
 
53
54
  import './theme/index.scss';
54
55
 
@@ -67,6 +68,7 @@ export default {
67
68
 
68
69
  app.component('m-form', Form);
69
70
  app.component('m-form-dialog', FormDialog);
71
+ app.component('m-form-drawer', FormDrawer);
70
72
  app.component('m-form-container', Container);
71
73
  app.component('m-form-fieldset', Fieldset);
72
74
  app.component('m-form-group-list', TableGroupList);
@@ -22,4 +22,7 @@
22
22
  background: #f7dadd;
23
23
  }
24
24
  }
25
+ .m-form-title-extra {
26
+ margin-left: 8px;
27
+ }
25
28
  }