mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-03-19 04:03:47 +00:00
feat(editor,form): 支持按需设置表单组件
This commit is contained in:
parent
88e6c7d377
commit
c79034befc
@ -189,6 +189,8 @@
|
||||
import hljs from 'highlight.js';
|
||||
import serialize from 'serialize-javascript';
|
||||
|
||||
import { MForm } from '@tmagic/form';
|
||||
|
||||
export function stripScript(content) {
|
||||
const result = content.match(/<(script)>([\s\S]+)<\/\1>/);
|
||||
return result && result[2] ? result[2].trim() : '';
|
||||
@ -210,6 +212,10 @@ export function stripTemplate(content) {
|
||||
export default {
|
||||
props: ['type', 'config'],
|
||||
|
||||
components: {
|
||||
MForm,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
codepen: {
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<m-fields-link :config="formConfig" :model="modelValue" name="form" @change="changeHandler"></m-fields-link>
|
||||
<MLink :config="formConfig" :model="modelValue" name="form" @change="changeHandler"></MLink>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, reactive, watch } from 'vue';
|
||||
import serialize from 'serialize-javascript';
|
||||
|
||||
import type { CodeLinkConfig, FieldProps } from '@tmagic/form';
|
||||
import type { CodeLinkConfig, FieldProps, MLink } from '@tmagic/form';
|
||||
|
||||
import { getEditorConfig } from '@editor/utils/config';
|
||||
|
||||
|
||||
@ -47,7 +47,13 @@ import { Coin } from '@element-plus/icons-vue';
|
||||
|
||||
import { DataSchema } from '@tmagic/core';
|
||||
import { TMagicButton, tMagicMessage, TMagicTooltip } from '@tmagic/design';
|
||||
import type { ContainerChangeEventData, DataSourceFieldSelectConfig, FieldProps, FormState } from '@tmagic/form';
|
||||
import {
|
||||
type ContainerChangeEventData,
|
||||
type DataSourceFieldSelectConfig,
|
||||
type FieldProps,
|
||||
type FormState,
|
||||
getFormField,
|
||||
} from '@tmagic/form';
|
||||
import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, removeDataSourceFieldPrefix } from '@tmagic/utils';
|
||||
|
||||
import MIcon from '@editor/components/Icon.vue';
|
||||
@ -104,7 +110,9 @@ const type = computed((): string => {
|
||||
});
|
||||
|
||||
const tagName = computed(() => {
|
||||
const component = resolveComponent(`m-${props.config.items ? 'form' : 'fields'}-${type.value}`);
|
||||
const component =
|
||||
getFormField(type.value || 'container') ||
|
||||
resolveComponent(`m-${props.config.items ? 'form' : 'fields'}-${type.value}`);
|
||||
if (typeof component !== 'string') return component;
|
||||
return 'm-fields-text';
|
||||
});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="m-fields-event-select">
|
||||
<m-form-table
|
||||
<MTable
|
||||
v-if="isOldVersion"
|
||||
name="events"
|
||||
:size="size"
|
||||
@ -8,7 +8,7 @@
|
||||
:model="model"
|
||||
:config="tableConfig"
|
||||
@change="onChangeHandler"
|
||||
></m-form-table>
|
||||
></MTable>
|
||||
|
||||
<div v-else class="fullWidth">
|
||||
<TMagicButton class="create-button" type="primary" :size="size" :disabled="disabled" @click="addEvent()"
|
||||
@ -68,8 +68,9 @@ import type {
|
||||
FormState,
|
||||
OnChangeHandlerData,
|
||||
PanelConfig,
|
||||
TableConfig,
|
||||
} from '@tmagic/form';
|
||||
import { MContainer as MFormContainer, MPanel } from '@tmagic/form';
|
||||
import { MContainer as MFormContainer, MPanel, MTable } from '@tmagic/form';
|
||||
import { DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX, traverseNode } from '@tmagic/utils';
|
||||
|
||||
import { useServices } from '@editor/hooks/use-services';
|
||||
@ -304,7 +305,7 @@ const dataSourceActionConfig = computed(() => {
|
||||
});
|
||||
|
||||
// 兼容旧的数据格式
|
||||
const tableConfig = computed(() => ({
|
||||
const tableConfig = computed<TableConfig>(() => ({
|
||||
type: 'table',
|
||||
name: 'events',
|
||||
items: [
|
||||
|
||||
@ -15,38 +15,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import type { App } from 'vue';
|
||||
|
||||
import type { DesignPluginOptions } from '@tmagic/design';
|
||||
import designPlugin from '@tmagic/design';
|
||||
import type { FormInstallOptions } from '@tmagic/form';
|
||||
import formPlugin from '@tmagic/form';
|
||||
import tablePlugin from '@tmagic/table';
|
||||
|
||||
import Code from './fields/Code.vue';
|
||||
import CodeLink from './fields/CodeLink.vue';
|
||||
import CodeSelect from './fields/CodeSelect.vue';
|
||||
import CodeSelectCol from './fields/CodeSelectCol.vue';
|
||||
import CondOpSelect from './fields/CondOpSelect.vue';
|
||||
import DataSourceFields from './fields/DataSourceFields.vue';
|
||||
import DataSourceFieldSelect from './fields/DataSourceFieldSelect/Index.vue';
|
||||
import DataSourceInput from './fields/DataSourceInput.vue';
|
||||
import DataSourceMethods from './fields/DataSourceMethods.vue';
|
||||
import DataSourceMethodSelect from './fields/DataSourceMethodSelect.vue';
|
||||
import DataSourceMocks from './fields/DataSourceMocks.vue';
|
||||
import DataSourceSelect from './fields/DataSourceSelect.vue';
|
||||
import DisplayConds from './fields/DisplayConds.vue';
|
||||
import EventSelect from './fields/EventSelect.vue';
|
||||
import KeyValue from './fields/KeyValue.vue';
|
||||
import PageFragmentSelect from './fields/PageFragmentSelect.vue';
|
||||
import StyleSetter from './fields/StyleSetter/Index.vue';
|
||||
import uiSelect from './fields/UISelect.vue';
|
||||
import CodeEditor from './layouts/CodeEditor.vue';
|
||||
import { setEditorConfig } from './utils/config';
|
||||
import Editor from './Editor.vue';
|
||||
import type { EditorInstallOptions } from './type';
|
||||
|
||||
import './theme/index.scss';
|
||||
|
||||
export * from '@tmagic/form';
|
||||
export { default as formPlugin } from '@tmagic/form';
|
||||
@ -110,44 +78,4 @@ export { default as DisplayConds } from './fields/DisplayConds.vue';
|
||||
export { default as CondOpSelect } from './fields/CondOpSelect.vue';
|
||||
export { default as StyleSetter } from './fields/StyleSetter/Index.vue';
|
||||
|
||||
const defaultInstallOpt: EditorInstallOptions = {
|
||||
// eslint-disable-next-line no-eval
|
||||
parseDSL: (dsl: string) => eval(dsl),
|
||||
customCreateMonacoEditor: (monaco, codeEditorEl, options) => monaco.editor.create(codeEditorEl, options),
|
||||
customCreateMonacoDiffEditor: (monaco, codeEditorEl, options) =>
|
||||
monaco.editor.createDiffEditor(codeEditorEl, options),
|
||||
};
|
||||
|
||||
export default {
|
||||
install: (app: App, opt?: Partial<EditorInstallOptions | DesignPluginOptions | FormInstallOptions>): void => {
|
||||
const option = Object.assign(defaultInstallOpt, opt || {});
|
||||
|
||||
app.use(designPlugin, opt || {});
|
||||
app.use(formPlugin, opt || {});
|
||||
app.use(tablePlugin);
|
||||
|
||||
app.config.globalProperties.$TMAGIC_EDITOR = option;
|
||||
setEditorConfig(option);
|
||||
|
||||
app.component(`${Editor.name || 'MEditor'}`, Editor);
|
||||
app.component('magic-code-editor', CodeEditor);
|
||||
app.component('m-fields-ui-select', uiSelect);
|
||||
app.component('m-fields-code-link', CodeLink);
|
||||
app.component('m-fields-vs-code', Code);
|
||||
app.component('m-fields-code-select', CodeSelect);
|
||||
app.component('m-fields-code-select-col', CodeSelectCol);
|
||||
app.component('m-fields-event-select', EventSelect);
|
||||
app.component('m-fields-data-source-fields', DataSourceFields);
|
||||
app.component('m-fields-data-source-mocks', DataSourceMocks);
|
||||
app.component('m-fields-key-value', KeyValue);
|
||||
app.component('m-fields-data-source-input', DataSourceInput);
|
||||
app.component('m-fields-data-source-select', DataSourceSelect);
|
||||
app.component('m-fields-data-source-methods', DataSourceMethods);
|
||||
app.component('m-fields-data-source-method-select', DataSourceMethodSelect);
|
||||
app.component('m-fields-data-source-field-select', DataSourceFieldSelect);
|
||||
app.component('m-fields-page-fragment-select', PageFragmentSelect);
|
||||
app.component('m-fields-display-conds', DisplayConds);
|
||||
app.component('m-fields-cond-op-select', CondOpSelect);
|
||||
app.component('m-form-style-setter', StyleSetter);
|
||||
},
|
||||
};
|
||||
export { default } from './plugin';
|
||||
|
||||
92
packages/editor/src/plugin.ts
Normal file
92
packages/editor/src/plugin.ts
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||
*
|
||||
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { App } from 'vue';
|
||||
|
||||
import type { DesignPluginOptions } from '@tmagic/design';
|
||||
import designPlugin from '@tmagic/design';
|
||||
import type { FormInstallOptions } from '@tmagic/form';
|
||||
import formPlugin from '@tmagic/form';
|
||||
import tablePlugin from '@tmagic/table';
|
||||
|
||||
import Code from './fields/Code.vue';
|
||||
import CodeLink from './fields/CodeLink.vue';
|
||||
import CodeSelect from './fields/CodeSelect.vue';
|
||||
import CodeSelectCol from './fields/CodeSelectCol.vue';
|
||||
import CondOpSelect from './fields/CondOpSelect.vue';
|
||||
import DataSourceFields from './fields/DataSourceFields.vue';
|
||||
import DataSourceFieldSelect from './fields/DataSourceFieldSelect/Index.vue';
|
||||
import DataSourceInput from './fields/DataSourceInput.vue';
|
||||
import DataSourceMethods from './fields/DataSourceMethods.vue';
|
||||
import DataSourceMethodSelect from './fields/DataSourceMethodSelect.vue';
|
||||
import DataSourceMocks from './fields/DataSourceMocks.vue';
|
||||
import DataSourceSelect from './fields/DataSourceSelect.vue';
|
||||
import DisplayConds from './fields/DisplayConds.vue';
|
||||
import EventSelect from './fields/EventSelect.vue';
|
||||
import KeyValue from './fields/KeyValue.vue';
|
||||
import PageFragmentSelect from './fields/PageFragmentSelect.vue';
|
||||
import StyleSetter from './fields/StyleSetter/Index.vue';
|
||||
import uiSelect from './fields/UISelect.vue';
|
||||
import CodeEditor from './layouts/CodeEditor.vue';
|
||||
import { setEditorConfig } from './utils/config';
|
||||
import Editor from './Editor.vue';
|
||||
import type { EditorInstallOptions } from './type';
|
||||
|
||||
import './theme/index.scss';
|
||||
|
||||
const defaultInstallOpt: EditorInstallOptions = {
|
||||
// eslint-disable-next-line no-eval
|
||||
parseDSL: (dsl: string) => eval(dsl),
|
||||
customCreateMonacoEditor: (monaco, codeEditorEl, options) => monaco.editor.create(codeEditorEl, options),
|
||||
customCreateMonacoDiffEditor: (monaco, codeEditorEl, options) =>
|
||||
monaco.editor.createDiffEditor(codeEditorEl, options),
|
||||
};
|
||||
|
||||
export default {
|
||||
install: (app: App, opt?: Partial<EditorInstallOptions | DesignPluginOptions | FormInstallOptions>): void => {
|
||||
const option = Object.assign(defaultInstallOpt, opt || {});
|
||||
|
||||
app.use(designPlugin, opt || {});
|
||||
app.use(formPlugin, opt || {});
|
||||
app.use(tablePlugin);
|
||||
|
||||
app.config.globalProperties.$TMAGIC_EDITOR = option;
|
||||
setEditorConfig(option);
|
||||
|
||||
app.component(`${Editor.name || 'MEditor'}`, Editor);
|
||||
app.component('magic-code-editor', CodeEditor);
|
||||
app.component('m-fields-ui-select', uiSelect);
|
||||
app.component('m-fields-code-link', CodeLink);
|
||||
app.component('m-fields-vs-code', Code);
|
||||
app.component('m-fields-code-select', CodeSelect);
|
||||
app.component('m-fields-code-select-col', CodeSelectCol);
|
||||
app.component('m-fields-event-select', EventSelect);
|
||||
app.component('m-fields-data-source-fields', DataSourceFields);
|
||||
app.component('m-fields-data-source-mocks', DataSourceMocks);
|
||||
app.component('m-fields-key-value', KeyValue);
|
||||
app.component('m-fields-data-source-input', DataSourceInput);
|
||||
app.component('m-fields-data-source-select', DataSourceSelect);
|
||||
app.component('m-fields-data-source-methods', DataSourceMethods);
|
||||
app.component('m-fields-data-source-method-select', DataSourceMethodSelect);
|
||||
app.component('m-fields-data-source-field-select', DataSourceFieldSelect);
|
||||
app.component('m-fields-page-fragment-select', PageFragmentSelect);
|
||||
app.component('m-fields-display-conds', DisplayConds);
|
||||
app.component('m-fields-cond-op-select', CondOpSelect);
|
||||
app.component('m-form-style-setter', StyleSetter);
|
||||
},
|
||||
};
|
||||
@ -19,7 +19,7 @@
|
||||
import type { Component } from 'vue';
|
||||
import type EventEmitter from 'events';
|
||||
import type * as Monaco from 'monaco-editor';
|
||||
import Sortable, { type Options, type SortableEvent } from 'sortablejs';
|
||||
import type { default as Sortable, Options, SortableEvent } from 'sortablejs';
|
||||
import type { PascalCasedProperties } from 'type-fest';
|
||||
|
||||
import type { CodeBlockContent, CodeBlockDSL, Id, MApp, MContainer, MNode, MPage, MPageFragment } from '@tmagic/core';
|
||||
|
||||
@ -27,3 +27,4 @@ export * from './scroll-viewer';
|
||||
export * from './tree';
|
||||
export * from './undo-redo';
|
||||
export * from './const';
|
||||
export { default as loadMonaco } from './monaco-editor';
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
:class="`m-form-container m-container-${type || ''} ${config.className || ''}${config.tip ? ' has-tip' : ''}`"
|
||||
:style="config.style"
|
||||
>
|
||||
<m-fields-hidden v-if="type === 'hidden'" v-bind="fieldsProps" :model="model"></m-fields-hidden>
|
||||
<MHidden v-if="type === 'hidden'" :name="`${name}`" :prop="itemProp" :model="model"></MHidden>
|
||||
|
||||
<component
|
||||
v-else-if="items && !text && type && display"
|
||||
@ -172,6 +172,7 @@ import { isEqual } from 'lodash-es';
|
||||
import { TMagicButton, TMagicFormItem, TMagicIcon, TMagicTooltip } from '@tmagic/design';
|
||||
import { getValueByKeyPath } from '@tmagic/utils';
|
||||
|
||||
import MHidden from '../fields/Hidden.vue';
|
||||
import type {
|
||||
ChildConfig,
|
||||
ContainerChangeEventData,
|
||||
@ -180,6 +181,7 @@ import type {
|
||||
FormValue,
|
||||
ToolTipConfigType,
|
||||
} from '../schema';
|
||||
import { getField } from '../utils/config';
|
||||
import { createObjectProp, display as displayFunction, filterFunction, getRules } from '../utils/form';
|
||||
|
||||
import FormLabel from './FormLabel.vue';
|
||||
@ -248,11 +250,23 @@ const itemProp = computed(() => {
|
||||
return `${n}`;
|
||||
});
|
||||
|
||||
const type = computed((): string => {
|
||||
let { type } = props.config;
|
||||
type = type && filterFunction<string>(mForm, type, props);
|
||||
if (type === 'form') return '';
|
||||
if (type === 'container') return '';
|
||||
return type?.replace(/([A-Z])/g, '-$1').toLowerCase() || (items.value ? '' : 'text');
|
||||
});
|
||||
|
||||
const tagName = computed(() => {
|
||||
if (type.value === 'component' && props.config.component) {
|
||||
return props.config.component;
|
||||
}
|
||||
return `m-${items.value ? 'form' : 'fields'}-${type.value}`;
|
||||
|
||||
if (!getField(type.value || 'container')) {
|
||||
console.log(type.value, 'type.value');
|
||||
}
|
||||
return getField(type.value || 'container') || `m-${items.value ? 'form' : 'fields'}-${type.value}`;
|
||||
});
|
||||
|
||||
const disabled = computed(() => props.disabled || filterFunction(mForm, props.config.disabled, props));
|
||||
@ -276,14 +290,6 @@ const tooltip = computed(() => {
|
||||
|
||||
const rule = computed(() => getRules(mForm, props.config.rules, props));
|
||||
|
||||
const type = computed((): string => {
|
||||
let { type } = props.config;
|
||||
type = type && filterFunction<string>(mForm, type, props);
|
||||
if (type === 'form') return '';
|
||||
if (type === 'container') return '';
|
||||
return type?.replace(/([A-Z])/g, '-$1').toLowerCase() || (items.value ? '' : 'text');
|
||||
});
|
||||
|
||||
const display = computed((): boolean => {
|
||||
const value = displayFunction(mForm, props.config.display, props);
|
||||
|
||||
|
||||
@ -3,14 +3,18 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { FieldProps, HiddenConfig } from '../schema';
|
||||
import type { FormValue } from '../schema';
|
||||
import { useAddField } from '../utils/useAddField';
|
||||
|
||||
defineOptions({
|
||||
name: 'MFormHidden',
|
||||
});
|
||||
|
||||
const props = defineProps<FieldProps<HiddenConfig>>();
|
||||
const props = defineProps<{
|
||||
model: FormValue;
|
||||
name: string;
|
||||
prop: string;
|
||||
}>();
|
||||
|
||||
useAddField(props.prop);
|
||||
</script>
|
||||
|
||||
@ -16,44 +16,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { App } from 'vue';
|
||||
|
||||
import Container from './containers/Container.vue';
|
||||
import Fieldset from './containers/Fieldset.vue';
|
||||
import FlexLayout from './containers/FlexLayout.vue';
|
||||
import GroupList from './containers/GroupList.vue';
|
||||
import Panel from './containers/Panel.vue';
|
||||
import Row from './containers/Row.vue';
|
||||
import MStep from './containers/Step.vue';
|
||||
import Tabs from './containers/Tabs.vue';
|
||||
import Cascader from './fields/Cascader.vue';
|
||||
import Checkbox from './fields/Checkbox.vue';
|
||||
import CheckboxGroup from './fields/CheckboxGroup.vue';
|
||||
import ColorPicker from './fields/ColorPicker.vue';
|
||||
import Date from './fields/Date.vue';
|
||||
import Daterange from './fields/Daterange.vue';
|
||||
import DateTime from './fields/DateTime.vue';
|
||||
import Display from './fields/Display.vue';
|
||||
import DynamicField from './fields/DynamicField.vue';
|
||||
import Hidden from './fields/Hidden.vue';
|
||||
import Link from './fields/Link.vue';
|
||||
import Number from './fields/Number.vue';
|
||||
import NumberRange from './fields/NumberRange.vue';
|
||||
import RadioGroup from './fields/RadioGroup.vue';
|
||||
import Select from './fields/Select.vue';
|
||||
import Switch from './fields/Switch.vue';
|
||||
import Text from './fields/Text.vue';
|
||||
import Textarea from './fields/Textarea.vue';
|
||||
import Time from './fields/Time.vue';
|
||||
import Timerange from './fields/Timerange.vue';
|
||||
import Table from './table/Table.vue';
|
||||
import { setConfig } from './utils/config';
|
||||
import Form from './Form.vue';
|
||||
import FormDialog from './FormDialog.vue';
|
||||
import type { FormConfig } from './schema';
|
||||
|
||||
import './theme/index.scss';
|
||||
|
||||
export * from './schema';
|
||||
export * from './utils/form';
|
||||
export * from './utils/useAddField';
|
||||
@ -91,52 +55,14 @@ export { default as MSelect } from './fields/Select.vue';
|
||||
export { default as MCascader } from './fields/Cascader.vue';
|
||||
export { default as MDynamicField } from './fields/DynamicField.vue';
|
||||
|
||||
export {
|
||||
deleteField as deleteFormField,
|
||||
getField as getFormField,
|
||||
registerField as registerFormField,
|
||||
} from './utils/config';
|
||||
|
||||
export type { FormInstallOptions } from './plugin';
|
||||
|
||||
export const createForm = <T extends [] = []>(config: FormConfig | T) => config;
|
||||
|
||||
export interface FormInstallOptions {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const defaultInstallOpt: FormInstallOptions = {};
|
||||
|
||||
export default {
|
||||
install(app: App, opt: FormInstallOptions = {}) {
|
||||
const option = Object.assign(defaultInstallOpt, opt);
|
||||
|
||||
app.config.globalProperties.$MAGIC_FORM = option;
|
||||
setConfig(option);
|
||||
|
||||
app.component('m-form', Form);
|
||||
app.component('m-form-dialog', FormDialog);
|
||||
app.component('m-form-container', Container);
|
||||
app.component('m-form-fieldset', Fieldset);
|
||||
app.component('m-form-group-list', GroupList);
|
||||
app.component('m-form-panel', Panel);
|
||||
app.component('m-form-row', Row);
|
||||
app.component('m-form-step', MStep);
|
||||
app.component('m-form-table', Table);
|
||||
app.component('m-form-tab', Tabs);
|
||||
app.component('m-form-flex-layout', FlexLayout);
|
||||
app.component('m-fields-text', Text);
|
||||
app.component('m-fields-img-upload', Text);
|
||||
app.component('m-fields-number', Number);
|
||||
app.component('m-fields-number-range', NumberRange);
|
||||
app.component('m-fields-textarea', Textarea);
|
||||
app.component('m-fields-hidden', Hidden);
|
||||
app.component('m-fields-date', Date);
|
||||
app.component('m-fields-datetime', DateTime);
|
||||
app.component('m-fields-daterange', Daterange);
|
||||
app.component('m-fields-timerange', Timerange);
|
||||
app.component('m-fields-time', Time);
|
||||
app.component('m-fields-checkbox', Checkbox);
|
||||
app.component('m-fields-switch', Switch);
|
||||
app.component('m-fields-color-picker', ColorPicker);
|
||||
app.component('m-fields-checkbox-group', CheckboxGroup);
|
||||
app.component('m-fields-radio-group', RadioGroup);
|
||||
app.component('m-fields-display', Display);
|
||||
app.component('m-fields-link', Link);
|
||||
app.component('m-fields-select', Select);
|
||||
app.component('m-fields-cascader', Cascader);
|
||||
app.component('m-fields-dynamic-field', DynamicField);
|
||||
},
|
||||
};
|
||||
export { default } from './plugin';
|
||||
|
||||
102
packages/form/src/plugin.ts
Normal file
102
packages/form/src/plugin.ts
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||
*
|
||||
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type App } from 'vue';
|
||||
|
||||
import Container from './containers/Container.vue';
|
||||
import Fieldset from './containers/Fieldset.vue';
|
||||
import FlexLayout from './containers/FlexLayout.vue';
|
||||
import GroupList from './containers/GroupList.vue';
|
||||
import Panel from './containers/Panel.vue';
|
||||
import Row from './containers/Row.vue';
|
||||
import MStep from './containers/Step.vue';
|
||||
import Tabs from './containers/Tabs.vue';
|
||||
import Cascader from './fields/Cascader.vue';
|
||||
import Checkbox from './fields/Checkbox.vue';
|
||||
import CheckboxGroup from './fields/CheckboxGroup.vue';
|
||||
import ColorPicker from './fields/ColorPicker.vue';
|
||||
import Date from './fields/Date.vue';
|
||||
import Daterange from './fields/Daterange.vue';
|
||||
import DateTime from './fields/DateTime.vue';
|
||||
import Display from './fields/Display.vue';
|
||||
import DynamicField from './fields/DynamicField.vue';
|
||||
import Hidden from './fields/Hidden.vue';
|
||||
import Link from './fields/Link.vue';
|
||||
import Number from './fields/Number.vue';
|
||||
import NumberRange from './fields/NumberRange.vue';
|
||||
import RadioGroup from './fields/RadioGroup.vue';
|
||||
import Select from './fields/Select.vue';
|
||||
import Switch from './fields/Switch.vue';
|
||||
import Text from './fields/Text.vue';
|
||||
import Textarea from './fields/Textarea.vue';
|
||||
import Time from './fields/Time.vue';
|
||||
import Timerange from './fields/Timerange.vue';
|
||||
import Table from './table/Table.vue';
|
||||
import { setConfig } from './utils/config';
|
||||
import Form from './Form.vue';
|
||||
import FormDialog from './FormDialog.vue';
|
||||
|
||||
import './theme/index.scss';
|
||||
|
||||
export interface FormInstallOptions {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const defaultInstallOpt: FormInstallOptions = {};
|
||||
|
||||
export default {
|
||||
install(app: App, opt: FormInstallOptions = {}) {
|
||||
const option = Object.assign(defaultInstallOpt, opt);
|
||||
|
||||
app.config.globalProperties.$MAGIC_FORM = option;
|
||||
setConfig(option);
|
||||
|
||||
app.component('m-form', Form);
|
||||
app.component('m-form-dialog', FormDialog);
|
||||
app.component('m-form-container', Container);
|
||||
app.component('m-form-fieldset', Fieldset);
|
||||
app.component('m-form-group-list', GroupList);
|
||||
app.component('m-form-panel', Panel);
|
||||
app.component('m-form-row', Row);
|
||||
app.component('m-form-step', MStep);
|
||||
app.component('m-form-table', Table);
|
||||
app.component('m-form-tab', Tabs);
|
||||
app.component('m-form-flex-layout', FlexLayout);
|
||||
app.component('m-fields-text', Text);
|
||||
app.component('m-fields-img-upload', Text);
|
||||
app.component('m-fields-number', Number);
|
||||
app.component('m-fields-number-range', NumberRange);
|
||||
app.component('m-fields-textarea', Textarea);
|
||||
app.component('m-fields-hidden', Hidden);
|
||||
app.component('m-fields-date', Date);
|
||||
app.component('m-fields-datetime', DateTime);
|
||||
app.component('m-fields-daterange', Daterange);
|
||||
app.component('m-fields-timerange', Timerange);
|
||||
app.component('m-fields-time', Time);
|
||||
app.component('m-fields-checkbox', Checkbox);
|
||||
app.component('m-fields-switch', Switch);
|
||||
app.component('m-fields-color-picker', ColorPicker);
|
||||
app.component('m-fields-checkbox-group', CheckboxGroup);
|
||||
app.component('m-fields-radio-group', RadioGroup);
|
||||
app.component('m-fields-display', Display);
|
||||
app.component('m-fields-link', Link);
|
||||
app.component('m-fields-select', Select);
|
||||
app.component('m-fields-cascader', Cascader);
|
||||
app.component('m-fields-dynamic-field', DynamicField);
|
||||
},
|
||||
};
|
||||
@ -1,5 +1,5 @@
|
||||
import { inject, nextTick, type Ref, type ShallowRef, watchEffect } from 'vue';
|
||||
import Sortable, { type SortableEvent } from 'sortablejs';
|
||||
import type { default as SortableType, SortableEvent } from 'sortablejs';
|
||||
|
||||
import { type TMagicTable } from '@tmagic/design';
|
||||
import type { FormState } from '@tmagic/form-schema';
|
||||
@ -8,6 +8,9 @@ import { sortArray } from '../utils/form';
|
||||
|
||||
import type { TableProps } from './type';
|
||||
|
||||
let SortablePromise: Promise<typeof SortableType> | undefined;
|
||||
const loadSortable = () => (SortablePromise ??= import('sortablejs').then((m) => m.default));
|
||||
|
||||
export const useSortable = (
|
||||
props: TableProps,
|
||||
emit: (event: 'select' | 'change' | 'addDiffCount', ...args: any[]) => void,
|
||||
@ -17,15 +20,16 @@ export const useSortable = (
|
||||
) => {
|
||||
const mForm = inject<FormState | undefined>('mForm');
|
||||
|
||||
let sortable: Sortable | undefined;
|
||||
const rowDrop = () => {
|
||||
let sortable: SortableType | undefined;
|
||||
const rowDrop = async () => {
|
||||
sortable?.destroy();
|
||||
const tableEl = tMagicTableRef.value?.getEl();
|
||||
const tBodyEl = tableEl?.querySelector('.el-table__body > tbody') || tableEl?.querySelector('.t-table__body');
|
||||
if (!tBodyEl) {
|
||||
return;
|
||||
}
|
||||
sortable = Sortable.create(tBodyEl, {
|
||||
|
||||
sortable = (await loadSortable()).create(tBodyEl, {
|
||||
draggable: '.tmagic-design-table-row',
|
||||
filter: 'input', // 表单组件选字操作和触发拖拽会冲突,优先保证选字操作
|
||||
preventOnFilter: false, // 允许选字
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Component } from 'vue';
|
||||
|
||||
let $MAGIC_FORM = {} as any;
|
||||
|
||||
const setConfig = (option: any): void => {
|
||||
@ -24,4 +26,17 @@ const setConfig = (option: any): void => {
|
||||
|
||||
const getConfig = <T = unknown>(key: string): T => $MAGIC_FORM[key];
|
||||
|
||||
export { getConfig, setConfig };
|
||||
const fieldRegistry = new Map<string, Component>();
|
||||
|
||||
const registerField = (tagName: string, component: Component): void => {
|
||||
if (fieldRegistry.has(tagName)) {
|
||||
return;
|
||||
}
|
||||
fieldRegistry.set(tagName, component);
|
||||
};
|
||||
|
||||
const getField = (tagName: string): Component | undefined => fieldRegistry.get(tagName);
|
||||
|
||||
const deleteField = (tagName: string): boolean => fieldRegistry.delete(tagName);
|
||||
|
||||
export { deleteField, getConfig, getField, registerField, setConfig };
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<nav-menu :data="menu"></nav-menu>
|
||||
<div class="diff-form">
|
||||
<div>开启表单对比功能</div>
|
||||
<m-form
|
||||
<MForm
|
||||
ref="form"
|
||||
:config="diffFormConfig"
|
||||
:is-compare="true"
|
||||
@ -11,12 +11,12 @@
|
||||
:last-values="lastVersion"
|
||||
size="small"
|
||||
height="100%"
|
||||
></m-form>
|
||||
></MForm>
|
||||
</div>
|
||||
<div class="title">表单字段展示</div>
|
||||
<div class="form-content">
|
||||
<m-form ref="form" :config="config" :init-values="initValue" size="small" height="100%"></m-form>
|
||||
<magic-code-editor class="code-editor-content" :init-values="config" @save="change"></magic-code-editor>
|
||||
<MForm ref="form" :config="config" :init-values="initValue" size="small" height="100%"></MForm>
|
||||
<TMagicCodeEditor class="code-editor-content" :init-values="config" @save="change"></TMagicCodeEditor>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user