feat(form): 剥离element-plus依赖,使用tamgic-design

#401
This commit is contained in:
roymondchen 2022-10-11 15:25:54 +08:00 committed by jia000
parent c613b12f11
commit 3a1a9795f6
35 changed files with 2067 additions and 2528 deletions

View File

@ -35,14 +35,13 @@
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.0.9", "@element-plus/icons-vue": "^2.0.9",
"@tmagic/design": "1.2.0-beta.2",
"@tmagic/utils": "1.2.0-beta.2", "@tmagic/utils": "1.2.0-beta.2",
"element-plus": "^2.2.17",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"sortablejs": "^1.14.0", "sortablejs": "^1.14.0",
"vue": "^3.2.37" "vue": "^3.2.37"
}, },
"peerDependencies": { "peerDependencies": {
"element-plus": "^2.2.17",
"vue": "^3.2.37" "vue": "^3.2.37"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,7 +1,7 @@
<template> <template>
<el-form <TMagicForm
class="m-form" class="m-form"
ref="elForm" ref="tMagicForm"
:model="values" :model="values"
:label-width="labelWidth" :label-width="labelWidth"
:disabled="disabled" :disabled="disabled"
@ -10,7 +10,7 @@
:label-position="labelPosition" :label-position="labelPosition"
> >
<template v-if="initialized && Array.isArray(config)"> <template v-if="initialized && Array.isArray(config)">
<m-form-container <Container
v-for="(item, index) in config" v-for="(item, index) in config"
:key="item[keyProp] ?? index" :key="item[keyProp] ?? index"
:config="item" :config="item"
@ -19,175 +19,132 @@
:step-active="stepActive" :step-active="stepActive"
:size="size" :size="size"
@change="changeHandler" @change="changeHandler"
></m-form-container> ></Container>
</template> </template>
</el-form> </TMagicForm>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { defineComponent, PropType, provide, reactive, ref, toRaw, watch } from 'vue'; import { provide, reactive, ref, toRaw, watch } from 'vue';
import { cloneDeep, isEqual } from 'lodash-es'; import cloneDeep from 'lodash-es/cloneDeep';
import isEqual from 'lodash-es/isEqual';
import { TMagicForm } from '@tmagic/design';
import Container from './containers/Container.vue';
import { getConfig } from './utils/config'; import { getConfig } from './utils/config';
import { initValue } from './utils/form'; import { initValue } from './utils/form';
import { FormConfig, FormState, FormValue } from './schema'; import type { FormConfig, FormState, FormValue, ValidateError } from './schema';
interface ValidateError { const props = withDefaults(
message: string; defineProps<{
field: string; config: FormConfig;
} initValues: Object;
parentValues?: Object;
export default defineComponent({ labelWidth?: string;
name: 'm-form', disabled?: boolean;
height?: string;
props: { stepActive?: string | number;
// size?: 'small' | 'default' | 'large';
initValues: { inline?: boolean;
type: Object, labelPosition?: string;
required: true, keyProp?: string;
default: () => ({}), popperClass?: string;
}, }>(),
{
parentValues: { config: () => [],
type: Object, initValues: () => ({}),
default: () => ({}), parentValues: () => ({}),
}, labelWidth: '200px',
disabled: false,
// height: 'auto',
config: { stepActive: 1,
type: Array as PropType<FormConfig>, inline: false,
required: true, labelPosition: 'right',
default: () => [], keyProp: '__key',
},
labelWidth: {
type: String,
default: () => '200px',
},
disabled: {
type: Boolean,
default: () => false,
},
height: {
type: String,
default: () => 'auto',
},
stepActive: {
type: [String, Number],
default: () => 1,
},
size: {
type: String as PropType<'small' | 'default' | 'large'>,
},
inline: {
type: Boolean,
default: false,
},
labelPosition: {
type: String,
default: 'right',
},
keyProp: {
type: String,
default: '__key',
},
popperClass: {
type: String,
},
}, },
);
emits: ['change', 'field-input', 'field-change'], const emit = defineEmits(['change', 'field-input', 'field-change']);
setup(props, { emit }) { const tMagicForm = ref<InstanceType<typeof TMagicForm>>();
// InstanceType<typeof ElForm>types const initialized = ref(false);
const elForm = ref<any>(); const values = ref<FormValue>({});
const initialized = ref(false); const fields = new Map<string, any>();
const values = ref<FormValue>({});
const fields = new Map<string, any>();
const requestFuc = getConfig('request') as Function; const requestFuc = getConfig('request') as Function;
const formState: FormState = reactive<FormState>({ const formState: FormState = reactive<FormState>({
keyProp: props.keyProp, keyProp: props.keyProp,
popperClass: props.popperClass, popperClass: props.popperClass,
config: props.config, config: props.config,
initValues: props.initValues,
parentValues: props.parentValues,
values,
$emit: emit as (event: string, ...args: any[]) => void,
fields,
setField: (prop: string, field: any) => fields.set(prop, field),
getField: (prop: string) => fields.get(prop),
deleteField: (prop: string) => fields.delete(prop),
post: (options: any) => {
if (requestFuc) {
return requestFuc({
...options,
method: 'POST',
});
}
},
});
provide('mForm', formState);
watch(
[() => props.config, () => props.initValues],
([config], [preConfig]) => {
if (!isEqual(toRaw(config), toRaw(preConfig))) {
initialized.value = false;
}
initValue(formState, {
initValues: props.initValues, initValues: props.initValues,
parentValues: props.parentValues, config: props.config,
values, }).then((value) => {
$emit: emit as (event: string, ...args: any[]) => void, values.value = value;
fields, initialized.value = true;
setField: (prop: string, field: any) => fields.set(prop, field),
getField: (prop: string) => fields.get(prop),
deleteField: (prop: string) => fields.delete(prop),
post: (options: any) => {
if (requestFuc) {
return requestFuc({
...options,
method: 'POST',
});
}
},
}); });
},
{ immediate: true },
);
provide('mForm', formState); const changeHandler = () => {
emit('change', values.value);
};
watch( defineExpose({
[() => props.config, () => props.initValues], values,
([config], [preConfig]) => { formState,
if (!isEqual(toRaw(config), toRaw(preConfig))) { initialized,
initialized.value = false;
}
initValue(formState, { changeHandler,
initValues: props.initValues,
config: props.config, resetForm: () => tMagicForm.value?.resetFields(),
}).then((value) => {
values.value = value; submitForm: async (native?: boolean): Promise<any> => {
initialized.value = true; try {
await tMagicForm.value?.validate();
return native ? values.value : cloneDeep(toRaw(values.value));
} catch (invalidFields: any) {
const error: string[] = [];
Object.entries(invalidFields).forEach(([, ValidateError]) => {
(ValidateError as ValidateError[]).forEach(({ field, message }) => {
if (field && message) error.push(`${field} -> ${message}`);
if (field && !message) error.push(`${field} -> 出现错误`);
if (!field && message) error.push(`${message}`);
}); });
}, });
{ immediate: true }, throw new Error(error.join('<br>'));
); }
return {
initialized,
values,
elForm,
formState,
changeHandler: () => {
emit('change', values.value);
},
resetForm: () => elForm.value?.resetFields(),
submitForm: async (native?: boolean): Promise<any> => {
try {
await elForm.value?.validate();
return native ? values.value : cloneDeep(toRaw(values.value));
} catch (invalidFields: any) {
const error: string[] = [];
Object.entries(invalidFields).forEach(([, ValidateError]) => {
(ValidateError as ValidateError[]).forEach(({ field, message }) => {
if (field && message) error.push(`${field} -> ${message}`);
if (field && !message) error.push(`${field} -> 出现错误`);
if (!field && message) error.push(`${message}`);
});
});
throw new Error(error.join('<br>'));
}
},
};
}, },
}); });
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog <TMagicDialog
v-model="dialogVisible" v-model="dialogVisible"
class="m-form-dialog" class="m-form-dialog"
top="20px" top="20px"
@ -15,7 +15,7 @@
class="m-dialog-body" class="m-dialog-body"
:style="`max-height: ${bodyHeight}; overflow-y: auto; overflow-x: hidden;`" :style="`max-height: ${bodyHeight}; overflow-y: auto; overflow-x: hidden;`"
> >
<m-form <Form
v-model="stepActive" v-model="stepActive"
ref="form" ref="form"
:size="size" :size="size"
@ -24,150 +24,128 @@
:parent-values="parentValues" :parent-values="parentValues"
:label-width="labelWidth" :label-width="labelWidth"
@change="changeHandler" @change="changeHandler"
></m-form> ></Form>
<slot></slot> <slot></slot>
</div> </div>
<template #footer> <template #footer>
<el-row class="dialog-footer"> <TMagicRow class="dialog-footer">
<el-col :span="12" style="text-align: left"> <TMagicCol :span="12" style="text-align: left">
<div style="min-height: 1px"> <div style="min-height: 1px">
<slot name="left"></slot> <slot name="left"></slot>
</div> </div>
</el-col> </TMagicCol>
<el-col :span="12"> <TMagicCol :span="12">
<slot name="footer"> <slot name="footer">
<el-button @click="cancel" size="small"> </el-button> <TMagicButton @click="cancel" size="small"> </TMagicButton>
<el-button v-if="hasStep && stepActive > 1" type="info" size="small" @click="preStep">上一步</el-button> <TMagicButton v-if="hasStep && stepActive > 1" type="info" size="small" @click="preStep"
<el-button v-if="hasStep && stepCount > stepActive" type="info" size="small" @click="nextStep" >上一步</TMagicButton
>下一步</el-button
> >
<el-button v-else type="primary" size="small" :loading="saveFetch" @click="save">{{ <TMagicButton v-if="hasStep && stepCount > stepActive" type="info" size="small" @click="nextStep"
>下一步</TMagicButton
>
<TMagicButton v-else type="primary" size="small" :loading="saveFetch" @click="save">{{
confirmText confirmText
}}</el-button> }}</TMagicButton>
</slot> </slot>
</el-col> </TMagicCol>
</el-row> </TMagicRow>
</template> </template>
</el-dialog> </TMagicDialog>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { computed, defineComponent, PropType, ref } from 'vue'; import { computed, ref } from 'vue';
import { TMagicButton, TMagicCol, TMagicDialog, TMagicRow } from '@tmagic/design';
import Form from './Form.vue'; import Form from './Form.vue';
import { FormConfig, StepConfig } from './schema'; import { FormConfig, StepConfig } from './schema';
export default defineComponent({ const props = withDefaults(
name: 'm-form-dialog', defineProps<{
config?: FormConfig;
props: { values?: Object;
values: { parentValues?: Object;
type: Object, width?: string | number;
default: () => ({}), labelWidth?: string;
}, fullscreen?: boolean;
title?: string;
parentValues: { size?: 'small' | 'default' | 'large';
type: Object, confirmText?: string;
}, }>(),
{
width: [Number, String], config: () => [],
values: () => ({}),
fullscreen: Boolean, confirmText: '确定',
title: String,
config: {
type: Array as PropType<FormConfig>,
required: true,
default: () => [],
},
labelWidth: [Number, String],
size: String as PropType<'small' | 'default' | 'large'>,
confirmText: {
type: String,
default: '确定',
},
}, },
);
emits: ['close', 'submit', 'error', 'change'], const emit = defineEmits(['close', 'submit', 'error', 'change']);
setup(props, { emit }) { const form = ref<InstanceType<typeof Form>>();
const form = ref<InstanceType<typeof Form>>(); const dialogVisible = ref(false);
const dialogVisible = ref(false); const saveFetch = ref(false);
const saveFetch = ref(false); const stepActive = ref(1);
const stepActive = ref(1); const bodyHeight = ref(`${document.body.clientHeight - 194}px`);
const bodyHeight = ref(`${document.body.clientHeight - 194}px`);
const stepCount = computed(() => { const stepCount = computed(() => {
const { length } = props.config; const { length } = props.config;
for (let index = 0; index < length; index++) { for (let index = 0; index < length; index++) {
if (props.config[index].type === 'step') { if (props.config[index].type === 'step') {
return (props.config[index] as StepConfig).items.length; return (props.config[index] as StepConfig).items.length;
} }
} }
return 0; return 0;
}); });
const hasStep = computed(() => { const hasStep = computed(() => {
const { length } = props.config; const { length } = props.config;
for (let index = 0; index < length; index++) { for (let index = 0; index < length; index++) {
if (props.config[index].type === 'step') { if (props.config[index].type === 'step') {
return true; return true;
} }
} }
return false; return false;
}); });
const cancel = () => { const cancel = () => {
dialogVisible.value = false; dialogVisible.value = false;
}; };
const closeHandler = () => { const closeHandler = () => {
stepActive.value = 1; stepActive.value = 1;
emit('close'); emit('close');
}; };
const save = async () => { const save = async () => {
try { try {
const values = await form.value?.submitForm(); const values = await form.value?.submitForm();
emit('submit', values); emit('submit', values);
} catch (e) { } catch (e) {
emit('error', e); emit('error', e);
} }
}; };
const preStep = () => { const preStep = () => {
stepActive.value -= 1; stepActive.value -= 1;
}; };
const nextStep = () => { const nextStep = () => {
stepActive.value += 1; stepActive.value += 1;
}; };
const changeHandler = (value: any) => { const changeHandler = (value: any) => {
emit('change', value); emit('change', value);
}; };
return { defineExpose({
form, form,
saveFetch, saveFetch,
stepActive, dialogVisible,
dialogVisible,
bodyHeight, cancel,
stepCount, save,
hasStep,
cancel,
closeHandler,
save,
preStep,
nextStep,
changeHandler,
};
},
}); });
</script> </script>

View File

@ -1,6 +1,6 @@
<template> <template>
<el-col v-show="display && config.type !== 'hidden'" :span="span"> <TMagicCol v-show="display && config.type !== 'hidden'" :span="span">
<m-form-container <Container
:model="model" :model="model"
:config="config" :config="config"
:prop="prop" :prop="prop"
@ -8,49 +8,33 @@
:expand-more="expandMore" :expand-more="expandMore"
:size="size" :size="size"
@change="changeHandler" @change="changeHandler"
></m-form-container> ></Container>
</el-col> </TMagicCol>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { computed, defineComponent, inject, PropType } from 'vue'; import { computed, inject } from 'vue';
import { TMagicCol } from '@tmagic/design';
import { ChildConfig, FormState } from '../schema'; import { ChildConfig, FormState } from '../schema';
import { display as displayFunction } from '../utils/form'; import { display as displayFunction } from '../utils/form';
export default defineComponent({ import Container from './Container.vue';
props: {
labelWidth: String,
expandMore: Boolean,
span: Number,
model: { const props = defineProps<{
type: Object, model: any;
default: () => ({}), config: ChildConfig;
}, labelWidth?: string;
expandMore?: boolean;
span?: number;
size?: string;
prop?: string;
}>();
config: { const emit = defineEmits(['change']);
type: Object as PropType<ChildConfig>,
default: () => ({}),
},
prop: String, const mForm = inject<FormState | undefined>('mForm');
const display = computed(() => displayFunction(mForm, props.config.display, props));
size: String, const changeHandler = () => emit('change', props.model);
},
emits: ['change'],
setup(props, { emit }) {
const mForm = inject<FormState | undefined>('mForm');
const changeHandler = () => emit('change', props.model);
return {
mForm,
display: computed(() => displayFunction(mForm, props.config.display, props)),
changeHandler,
};
},
});
</script> </script>

View File

@ -30,7 +30,7 @@
></component> ></component>
<template v-else-if="type && display"> <template v-else-if="type && display">
<el-form-item <TMagicFormItem
:style="config.tip ? 'flex: 1' : ''" :style="config.tip ? 'flex: 1' : ''"
:class="{ hidden: `${itemLabelWidth}` === '0' || !config.text }" :class="{ hidden: `${itemLabelWidth}` === '0' || !config.text }"
:prop="itemProp" :prop="itemProp"
@ -38,7 +38,7 @@
:rules="rule" :rules="rule"
> >
<template #label><span v-html="type === 'checkbox' ? '' : config.text"></span></template> <template #label><span v-html="type === 'checkbox' ? '' : config.text"></span></template>
<el-tooltip v-if="tooltip"> <TMagicTooltip v-if="tooltip">
<component <component
:key="key(config)" :key="key(config)"
:size="size" :size="size"
@ -53,7 +53,7 @@
<template #content> <template #content>
<div v-html="tooltip"></div> <div v-html="tooltip"></div>
</template> </template>
</el-tooltip> </TMagicTooltip>
<component <component
v-else v-else
@ -69,19 +69,19 @@
></component> ></component>
<div v-if="extra" v-html="extra" class="m-form-tip"></div> <div v-if="extra" v-html="extra" class="m-form-tip"></div>
</el-form-item> </TMagicFormItem>
<el-tooltip v-if="config.tip" placement="left"> <TMagicTooltip v-if="config.tip" placement="left">
<el-icon style="line-height: 40px; margin-left: 5px"><warning-filled /></el-icon> <TMagicIcon style="line-height: 40px; margin-left: 5px"><warning-filled /></TMagicIcon>
<template #content> <template #content>
<div v-html="config.tip"></div> <div v-html="config.tip"></div>
</template> </template>
</el-tooltip> </TMagicTooltip>
</template> </template>
<template v-else-if="items && display"> <template v-else-if="items && display">
<template v-if="name || name === 0 ? model[name] : model"> <template v-if="name || name === 0 ? model[name] : model">
<m-form-container <Container
v-for="item in items" v-for="item in items"
:key="key(item)" :key="key(item)"
:model="name || name === 0 ? model[name] : model" :model="name || name === 0 ? model[name] : model"
@ -92,202 +92,166 @@
:label-width="itemLabelWidth" :label-width="itemLabelWidth"
:prop="itemProp" :prop="itemProp"
@change="onChangeHandler" @change="onChangeHandler"
></m-form-container> ></Container>
</template> </template>
</template> </template>
<div style="text-align: center" v-if="config.expand && type !== 'fieldset'"> <div style="text-align: center" v-if="config.expand && type !== 'fieldset'">
<el-button text @click="expandHandler">{{ expand ? '收起配置' : '展开更多配置' }}</el-button> <TMagicButton text @click="expandHandler">{{ expand ? '收起配置' : '展开更多配置' }}</TMagicButton>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { computed, defineComponent, inject, PropType, ref, resolveComponent, watchEffect } from 'vue'; import { computed, inject, ref, resolveComponent, watchEffect } from 'vue';
import { WarningFilled } from '@element-plus/icons-vue'; import { WarningFilled } from '@element-plus/icons-vue';
import { TMagicButton, TMagicFormItem, TMagicIcon, TMagicTooltip } from '@tmagic/design';
import { ChildConfig, ContainerCommonConfig, FormState, FormValue } from '../schema'; import { ChildConfig, ContainerCommonConfig, FormState, FormValue } from '../schema';
import { display as displayFunction, filterFunction, getRules } from '../utils/form'; import { display as displayFunction, filterFunction, getRules } from '../utils/form';
export default defineComponent({ const props = withDefaults(
name: 'm-form-container', defineProps<{
model: FormValue;
components: { WarningFilled }, config: ChildConfig;
prop?: string;
props: { labelWidth?: string;
labelWidth: String, expandMore?: boolean;
expandMore: Boolean, stepActive?: string | number;
size?: string;
model: { }>(),
type: [Object, Array] as PropType<FormValue>, {
required: true, prop: '',
}, size: 'small',
expandMore: false,
config: {
type: Object as PropType<ChildConfig>,
required: true,
},
prop: {
type: String,
default: () => '',
},
stepActive: {
type: [String, Number],
},
size: {
type: String,
default: 'small',
},
}, },
);
emits: ['change'], const emit = defineEmits(['change']);
setup(props, { emit }) { const mForm = inject<FormState | undefined>('mForm');
const mForm = inject<FormState | undefined>('mForm');
const expand = ref(false); const expand = ref(false);
const name = computed(() => props.config.name || ''); const name = computed(() => props.config.name || '');
const items = computed(() => (props.config as ContainerCommonConfig).items); const items = computed(() => (props.config as ContainerCommonConfig).items);
const itemProp = computed(() => { const itemProp = computed(() => {
let n: string | number = ''; let n: string | number = '';
const { names } = props.config as any; const { names } = props.config as any;
if (names?.[0]) { if (names?.[0]) {
[n] = names; [n] = names;
} else if (name.value) { } else if (name.value) {
n = name.value; n = name.value;
} else { } else {
return props.prop; return props.prop;
} }
return `${props.prop}${props.prop ? '.' : ''}${n}`; return `${props.prop}${props.prop ? '.' : ''}${n}`;
});
const tagName = computed(() => {
const component = resolveComponent(`m-${items.value ? 'form' : 'fields'}-${type.value}`);
if (typeof component !== 'string') return component;
return 'm-fields-text';
});
const disabled = computed(() => filterFunction(mForm, props.config.disabled, props));
const tooltip = computed(() => filterFunction(mForm, props.config.tooltip, props));
const extra = computed(() => filterFunction(mForm, props.config.extra, props));
const rule = computed(() => getRules(mForm, props.config.rules, props));
const type = computed((): string => {
let { type } = props.config;
if (typeof type === 'function') {
type = type(mForm, {
model: props.model,
});
}
if (type === 'form') return '';
return type?.replace(/([A-Z])/g, '-$1').toLowerCase() || (items.value ? '' : 'text');
});
const display = computed((): boolean => {
if (props.config.display === 'expand') {
return expand.value;
}
return displayFunction(mForm, props.config.display, props);
});
const itemLabelWidth = computed(() => props.config.labelWidth || props.labelWidth);
watchEffect(() => {
expand.value = props.expandMore;
});
const expandHandler = () => (expand.value = !expand.value);
const key = (config: any) => config[mForm?.keyProps];
const filterHandler = (filter: any, value: FormValue | number | string) => {
if (typeof filter === 'function') {
return filter(mForm, value, {
model: props.model,
values: mForm?.initValues,
formValue: mForm?.values,
prop: itemProp.value,
config: props.config,
});
}
if (filter === 'number') {
return +value;
}
return value;
};
const changeHandler = (onChange: any, value: FormValue | number | string) => {
if (typeof onChange === 'function') {
return onChange(mForm, value, {
model: props.model,
values: mForm?.initValues,
formValue: mForm?.values,
prop: itemProp.value,
config: props.config,
});
}
};
const trimHandler = (trim: any, value: FormValue | number | string) => {
if (typeof value === 'string' && trim) {
return value.replace(/^\s*/, '').replace(/\s*$/, '');
}
};
const onChangeHandler = async function (v: FormValue, key?: string) {
const { filter, onChange, trim, name, dynamicKey } = props.config as any;
let value: FormValue | number | string = v;
try {
value = filterHandler(filter, v);
value = (await changeHandler(onChange, value)) ?? value;
value = trimHandler(trim, value) ?? value;
} catch (e) {
console.error(e);
}
// fieldfield-linkmodel===value,
if ((name || name === 0) && props.model !== value && (v !== value || props.model[name] !== value)) {
// eslint-disable-next-line vue/no-mutating-props
props.model[name] = value;
}
// valuekeymodel
if (key !== undefined && dynamicKey) {
// eslint-disable-next-line vue/no-mutating-props
props.model[key] = value;
}
emit('change', props.model);
};
return {
expand,
name,
type,
disabled,
itemProp,
items,
display,
itemLabelWidth,
tagName,
rule,
tooltip,
extra,
key,
onChangeHandler,
expandHandler,
};
},
}); });
const tagName = computed(() => {
const component = resolveComponent(`m-${items.value ? 'form' : 'fields'}-${type.value}`);
if (typeof component !== 'string') return component;
return 'm-fields-text';
});
const disabled = computed(() => filterFunction(mForm, props.config.disabled, props));
const tooltip = computed(() => filterFunction(mForm, props.config.tooltip, props));
const extra = computed(() => filterFunction(mForm, props.config.extra, props));
const rule = computed(() => getRules(mForm, props.config.rules, props));
const type = computed((): string => {
let { type } = props.config;
if (typeof type === 'function') {
type = type(mForm, {
model: props.model,
});
}
if (type === 'form') return '';
return type?.replace(/([A-Z])/g, '-$1').toLowerCase() || (items.value ? '' : 'text');
});
const display = computed((): boolean => {
if (props.config.display === 'expand') {
return expand.value;
}
return displayFunction(mForm, props.config.display, props);
});
const itemLabelWidth = computed(() => props.config.labelWidth || props.labelWidth);
watchEffect(() => {
expand.value = props.expandMore;
});
const expandHandler = () => (expand.value = !expand.value);
const key = (config: any) => config[mForm?.keyProps];
const filterHandler = (filter: any, value: FormValue | number | string) => {
if (typeof filter === 'function') {
return filter(mForm, value, {
model: props.model,
values: mForm?.initValues,
formValue: mForm?.values,
prop: itemProp.value,
config: props.config,
});
}
if (filter === 'number') {
return +value;
}
return value;
};
const changeHandler = (onChange: any, value: FormValue | number | string) => {
if (typeof onChange === 'function') {
return onChange(mForm, value, {
model: props.model,
values: mForm?.initValues,
formValue: mForm?.values,
prop: itemProp.value,
config: props.config,
});
}
};
const trimHandler = (trim: any, value: FormValue | number | string) => {
if (typeof value === 'string' && trim) {
return value.replace(/^\s*/, '').replace(/\s*$/, '');
}
};
const onChangeHandler = async function (v: FormValue, key?: string) {
const { filter, onChange, trim, name, dynamicKey } = props.config as any;
let value: FormValue | number | string = v;
try {
value = filterHandler(filter, v);
value = (await changeHandler(onChange, value)) ?? value;
value = trimHandler(trim, value) ?? value;
} catch (e) {
console.error(e);
}
// fieldfield-linkmodel===value,
if ((name || name === 0) && props.model !== value && (v !== value || props.model[name] !== value)) {
// eslint-disable-next-line vue/no-mutating-props
props.model[name] = value;
}
// valuekeymodel
if (key !== undefined && dynamicKey) {
// eslint-disable-next-line vue/no-mutating-props
props.model[key] = value;
}
emit('change', props.model);
};
</script> </script>

View File

@ -5,13 +5,13 @@
:style="show ? 'padding: 15px 15px 0 5px;' : 'border: 0'" :style="show ? 'padding: 15px 15px 0 5px;' : 'border: 0'"
> >
<component v-if="name && config.checkbox" :is="!show ? 'div' : 'legend'"> <component v-if="name && config.checkbox" :is="!show ? 'div' : 'legend'">
<el-checkbox <TMagicCheckbox
v-model="model[name].value" v-model="model[name].value"
:prop="`${prop}${prop ? '.' : ''}${config.name}.value`" :prop="`${prop}${prop ? '.' : ''}${config.name}.value`"
:true-label="1" :true-label="1"
:false-label="0" :false-label="0"
><span v-html="config.legend"></span><span v-if="config.extra" v-html="config.extra" class="m-form-tip"></span ><span v-html="config.legend"></span><span v-if="config.extra" v-html="config.extra" class="m-form-tip"></span
></el-checkbox> ></TMagicCheckbox>
</component> </component>
<legend v-else> <legend v-else>
<span v-html="config.legend"></span> <span v-html="config.legend"></span>
@ -20,7 +20,7 @@
<div v-if="config.schematic && show" style="display: flex"> <div v-if="config.schematic && show" style="display: flex">
<div style="flex: 1"> <div style="flex: 1">
<m-form-container <Container
v-for="(item, index) in config.items" v-for="(item, index) in config.items"
:key="key(item, index)" :key="key(item, index)"
:model="name ? model[name] : model" :model="name ? model[name] : model"
@ -30,14 +30,14 @@
:labelWidth="lWidth" :labelWidth="lWidth"
:size="size" :size="size"
@change="change" @change="change"
></m-form-container> ></Container>
</div> </div>
<img class="m-form-schematic" :src="config.schematic" /> <img class="m-form-schematic" :src="config.schematic" />
</div> </div>
<template v-else-if="show"> <template v-else-if="show">
<m-form-container <Container
v-for="(item, index) in config.items" v-for="(item, index) in config.items"
:key="key(item, index)" :key="key(item, index)"
:model="name ? model[name] : model" :model="name ? model[name] : model"
@ -47,7 +47,7 @@
:labelWidth="lWidth" :labelWidth="lWidth"
:size="size" :size="size"
@change="change" @change="change"
></m-form-container> ></Container>
</template> </template>
</fieldset> </fieldset>
</template> </template>
@ -55,8 +55,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, inject, watch } from 'vue'; import { computed, inject, watch } from 'vue';
import { TMagicCheckbox } from '@tmagic/design';
import { FieldsetConfig, FormState } from '../schema'; import { FieldsetConfig, FormState } from '../schema';
import Container from './Container.vue';
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
labelWidth?: string; labelWidth?: string;
@ -89,7 +93,7 @@ const lWidth = computed(() => {
if (props.config.items) { if (props.config.items) {
return props.config.labelWidth || props.labelWidth; return props.config.labelWidth || props.labelWidth;
} }
return props.config.labelWidth || props.labelWidth || (props.config.text ? null : '0'); return props.config.labelWidth || props.labelWidth || (props.config.text ? undefined : '0');
}); });
const change = () => { const change = () => {

View File

@ -5,7 +5,7 @@
<span class="el-table__empty-text">暂无数据</span> <span class="el-table__empty-text">暂无数据</span>
</div> </div>
<m-fields-group-list-item <MFieldsGroupListItem
v-else v-else
v-for="(item, index) in model[name]" v-for="(item, index) in model[name]"
:key="index" :key="index"
@ -19,138 +19,106 @@
@remove-item="removeHandler" @remove-item="removeHandler"
@swap-item="swapHandler" @swap-item="swapHandler"
@change="changeHandler" @change="changeHandler"
></m-fields-group-list-item> ></MFieldsGroupListItem>
<el-button @click="addHandler" size="small" v-if="addable">添加组</el-button> <TMagicButton @click="addHandler" size="small" v-if="addable">添加组</TMagicButton>
<el-button :icon="Grid" size="small" @click="toggleMode" v-if="config.enableToggleMode">切换为表格</el-button> <TMagicButton :icon="Grid" size="small" @click="toggleMode" v-if="config.enableToggleMode">切换为表格</TMagicButton>
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { computed, defineComponent, inject, PropType } from 'vue'; import { computed, inject } from 'vue';
import { Grid } from '@element-plus/icons-vue'; import { Grid } from '@element-plus/icons-vue';
import { TMagicButton } from '@tmagic/design';
import { FormState, GroupListConfig } from '../schema'; import { FormState, GroupListConfig } from '../schema';
import { initValue } from '../utils/form'; import { initValue } from '../utils/form';
import MFieldsGroupListItem from './GroupListItem.vue'; import MFieldsGroupListItem from './GroupListItem.vue';
export default defineComponent({ const props = defineProps<{
name: 'm-form-group-list', model: any;
config: GroupListConfig;
name: string;
labelWidth?: string;
prop?: string;
size?: string;
}>();
components: { MFieldsGroupListItem }, const emit = defineEmits(['change']);
props: { const mForm = inject<FormState | undefined>('mForm');
labelWidth: String,
model: { const addable = computed(() => {
type: Object, if (!props.name) return false;
default: () => ({}),
},
config: { if (typeof props.config.addable === 'function') {
type: Object as PropType<GroupListConfig>, return props.config.addable(mForm, {
default: () => ({}), model: props.model[props.name],
}, formValue: mForm?.values,
prop: props.prop,
prop: { config: props.config,
type: String,
default: '',
},
size: String,
name: {
type: String,
default: '',
},
},
emits: ['change'],
setup(props, { emit }) {
const mForm = inject<FormState | undefined>('mForm');
const addable = computed(() => {
if (!props.name) return false;
if (typeof props.config.addable === 'function') {
return props.config.addable(mForm, {
model: props.model[props.name],
formValue: mForm?.values,
prop: props.prop,
config: props.config,
});
}
return typeof props.config.addable === 'undefined' ? true : props.config.addable;
}); });
}
const changeHandler = () => { return typeof props.config.addable === 'undefined' ? true : props.config.addable;
if (!props.name) return false;
emit('change', props.model[props.name]);
};
const addHandler = async () => {
if (!props.name) return false;
let initValues = {};
if (typeof props.config.defaultAdd === 'function') {
initValues = await props.config.defaultAdd(mForm, {
model: props.model[props.name],
formValue: mForm?.values,
prop: props.prop,
config: props.config,
});
} else if (props.config.defaultAdd) {
initValues = props.config.defaultAdd;
}
const groupValue = await initValue(mForm, {
config: props.config.items,
initValues,
});
props.model[props.name].push(groupValue);
};
const removeHandler = (index: number) => {
if (!props.name) return false;
props.model[props.name].splice(index, 1);
changeHandler();
};
const swapHandler = (idx1: number, idx2: number) => {
if (!props.name) return false;
const [currRow] = props.model[props.name].splice(idx1, 1);
props.model[props.name].splice(idx2, 0, currRow);
changeHandler();
};
const toggleMode = () => {
props.config.type = 'table';
props.config.groupItems = props.config.items;
props.config.items = (props.config.tableItems ||
props.config.items.map((item: any) => ({
...item,
label: item.label || item.text,
text: null,
}))) as any;
};
return {
Grid,
addable,
toggleMode,
removeHandler,
swapHandler,
changeHandler,
addHandler,
};
},
}); });
const changeHandler = () => {
if (!props.name) return false;
emit('change', props.model[props.name]);
};
const addHandler = async () => {
if (!props.name) return false;
let initValues = {};
if (typeof props.config.defaultAdd === 'function') {
initValues = await props.config.defaultAdd(mForm, {
model: props.model[props.name],
formValue: mForm?.values,
prop: props.prop,
config: props.config,
});
} else if (props.config.defaultAdd) {
initValues = props.config.defaultAdd;
}
const groupValue = await initValue(mForm, {
config: props.config.items,
initValues,
});
props.model[props.name].push(groupValue);
};
const removeHandler = (index: number) => {
if (!props.name) return false;
props.model[props.name].splice(index, 1);
changeHandler();
};
const swapHandler = (idx1: number, idx2: number) => {
if (!props.name) return false;
const [currRow] = props.model[props.name].splice(idx1, 1);
props.model[props.name].splice(idx2, 0, currRow);
changeHandler();
};
const toggleMode = () => {
props.config.type = 'table';
props.config.groupItems = props.config.items;
props.config.items = (props.config.tableItems ||
props.config.items.map((item: any) => ({
...item,
label: item.label || item.text,
text: null,
}))) as any;
};
</script> </script>

View File

@ -1,33 +1,33 @@
<template> <template>
<div class="m-fields-group-list-item"> <div class="m-fields-group-list-item">
<div> <div>
<el-icon style="margin-right: 7px" @click="expandHandler" <TMagicIcon style="margin-right: 7px" @click="expandHandler"
><CaretBottom v-if="expand" /><CaretRight v-else ><CaretBottom v-if="expand" /><CaretRight v-else
/></el-icon> /></TMagicIcon>
<el-button text @click="expandHandler">{{ title }}</el-button> <TMagicButton text @click="expandHandler">{{ title }}</TMagicButton>
<el-button <TMagicButton
v-show="showDelete(parseInt(String(index)))" v-show="showDelete(parseInt(String(index)))"
text text
:icon="Delete" :icon="Delete"
style="color: #f56c6c" style="color: #f56c6c"
@click="removeHandler" @click="removeHandler"
></el-button> ></TMagicButton>
<template v-if="movable()"> <template v-if="movable()">
<el-button v-show="index !== 0" text size="small" @click="changeOrder(-1)" <TMagicButton v-show="index !== 0" text size="small" @click="changeOrder(-1)"
>上移<el-icon><CaretTop /></el-icon >上移<TMagicIcon><CaretTop /></TMagicIcon
></el-button> ></TMagicButton>
<el-button v-show="index !== length - 1" text size="small" @click="changeOrder(1)" <TMagicButton v-show="index !== length - 1" text size="small" @click="changeOrder(1)"
>下移<el-icon><CaretBottom /></el-icon >下移<TMagicIcon><CaretBottom /></TMagicIcon
></el-button> ></TMagicButton>
</template> </template>
<span v-if="itemExtra" v-html="itemExtra" class="m-form-tip"></span> <span v-if="itemExtra" v-html="itemExtra" class="m-form-tip"></span>
</div> </div>
<m-form-container <Container
v-if="expand" v-if="expand"
:config="rowConfig" :config="rowConfig"
:model="model" :model="model"
@ -35,125 +35,88 @@
:prop="`${prop}${prop ? '.' : ''}${String(index)}`" :prop="`${prop}${prop ? '.' : ''}${String(index)}`"
:size="size" :size="size"
@change="changeHandler" @change="changeHandler"
></m-form-container> ></Container>
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { computed, defineComponent, inject, PropType, ref, watchEffect } from 'vue'; import { computed, inject, ref, watchEffect } from 'vue';
import { CaretBottom, CaretRight, CaretTop, Delete } from '@element-plus/icons-vue'; import { CaretBottom, CaretRight, CaretTop, Delete } from '@element-plus/icons-vue';
import { TMagicButton, TMagicIcon } from '@tmagic/design';
import { FormState, GroupListConfig } from '../schema'; import { FormState, GroupListConfig } from '../schema';
import { filterFunction } from '../utils/form'; import { filterFunction } from '../utils/form';
export default defineComponent({ import Container from './Container.vue';
name: 'm-form-group-list-item',
components: { CaretBottom, CaretRight, CaretTop }, const props = defineProps<{
model: any;
groupModel: any[];
config: GroupListConfig;
labelWidth?: string;
prop?: string;
size?: string;
index: number;
}>();
props: { const emit = defineEmits(['swap-item', 'remove-item', 'change']);
labelWidth: String,
model: { const mForm = inject<FormState | undefined>('mForm');
type: Object, const expand = ref(false);
default: () => ({}),
},
config: { watchEffect(() => {
type: Object as PropType<GroupListConfig>, expand.value = !props.index;
default: () => ({}),
},
prop: String,
size: String,
index: {
type: [Number, String, Symbol],
default: 0,
},
groupModel: {
type: Array,
default: () => [],
},
},
emits: ['swap-item', 'remove-item', 'change'],
setup(props, { emit }) {
const mForm = inject<FormState | undefined>('mForm');
const expand = ref(false);
watchEffect(() => {
expand.value = !props.index;
});
const rowConfig = computed(() => ({
type: 'row',
span: props.config.span || 24,
items: props.config.items,
labelWidth: props.config.labelWidth,
[mForm?.keyProp || '__key']: `${props.config[mForm?.keyProp || '__key']}${String(props.index)}`,
}));
const title = computed(() => {
if (props.config.titleKey && props.model[props.config.titleKey]) {
return props.model[props.config.titleKey];
}
return `${String(props.index)}`;
});
const length = computed(() => props.groupModel?.length || 0);
const itemExtra = computed(() => filterFunction(mForm, props.config.itemExtra, props));
const removeHandler = () => emit('remove-item', props.index);
const changeHandler = () => emit('change');
const expandHandler = () => {
expand.value = !expand.value;
};
//
const showDelete = (index: number) => {
const deleteFunc = props.config.delete;
if (deleteFunc && typeof deleteFunc === 'function') {
return deleteFunc(props.model, index, mForm?.values);
}
return true;
};
//
const changeOrder = (offset = 0) => emit('swap-item', props.index, `${String(props.index)}${offset}`);
const movable = () => {
const { movable } = props.config;
//
if (movable === undefined) return true;
if (typeof movable === 'function') {
return movable(mForm, props.index || 0, props.model, props.groupModel);
}
return movable;
};
return {
expand,
expandHandler,
title,
showDelete,
removeHandler,
movable,
changeOrder,
itemExtra,
rowConfig,
changeHandler,
length,
Delete,
};
},
}); });
const rowConfig = computed(() => ({
type: 'row',
span: props.config.span || 24,
items: props.config.items,
labelWidth: props.config.labelWidth,
[mForm?.keyProp || '__key']: `${props.config[mForm?.keyProp || '__key']}${String(props.index)}`,
}));
const title = computed(() => {
if (props.config.titleKey && props.model[props.config.titleKey]) {
return props.model[props.config.titleKey];
}
return `${String(props.index)}`;
});
const length = computed(() => props.groupModel?.length || 0);
const itemExtra = computed(() => filterFunction(mForm, props.config.itemExtra, props));
const removeHandler = () => emit('remove-item', props.index);
const changeHandler = () => emit('change');
const expandHandler = () => {
expand.value = !expand.value;
};
//
const showDelete = (index: number) => {
const deleteFunc = props.config.delete;
if (deleteFunc && typeof deleteFunc === 'function') {
return deleteFunc(props.model, index, mForm?.values);
}
return true;
};
//
const changeOrder = (offset = 0) => emit('swap-item', props.index, `${String(props.index)}${offset}`);
const movable = () => {
const { movable } = props.config;
//
if (movable === undefined) return true;
if (typeof movable === 'function') {
return movable(mForm, props.index || 0, props.model, props.groupModel);
}
return movable;
};
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-card <TMagicCard
v-if="items && items.length" v-if="items && items.length"
class="box-card m-form-panel" class="box-card m-form-panel"
:body-style="{ display: expand ? 'block' : 'none' }" :body-style="{ display: expand ? 'block' : 'none' }"
@ -7,7 +7,7 @@
<template #header> <template #header>
<div class="clearfix"> <div class="clearfix">
<a href="javascript:" style="width: 100%; display: block" @click="expand = !expand"> <a href="javascript:" style="width: 100%; display: block" @click="expand = !expand">
<el-icon><caret-bottom v-if="expand" /><caret-right v-else /></el-icon> {{ filter(config.title) }} <TMagicIcon><CaretBottom v-if="expand" /><CaretRight v-else /></TMagicIcon> {{ filter(config.title) }}
<span v-if="config && config.extra" v-html="config.extra" class="m-form-tip"></span> <span v-if="config && config.extra" v-html="config.extra" class="m-form-tip"></span>
</a> </a>
</div> </div>
@ -18,7 +18,7 @@
<div v-if="config.schematic" style="display: flex"> <div v-if="config.schematic" style="display: flex">
<div style="flex: 1"> <div style="flex: 1">
<m-form-container <Container
v-for="(item, index) in items" v-for="(item, index) in items"
:key="item[mForm?.keyProp || '__key'] ?? index" :key="item[mForm?.keyProp || '__key'] ?? index"
:config="item" :config="item"
@ -27,14 +27,14 @@
:size="size" :size="size"
:label-width="config.labelWidth || labelWidth" :label-width="config.labelWidth || labelWidth"
@change="changeHandler" @change="changeHandler"
></m-form-container> ></Container>
</div> </div>
<img class="m-form-schematic" :src="config.schematic" /> <img class="m-form-schematic" :src="config.schematic" />
</div> </div>
<template v-else> <template v-else>
<m-form-container <Container
v-for="(item, index) in items" v-for="(item, index) in items"
:key="item[mForm?.keyProp || '__key'] ?? index" :key="item[mForm?.keyProp || '__key'] ?? index"
:config="item" :config="item"
@ -43,64 +43,41 @@
:size="size" :size="size"
:label-width="config.labelWidth || labelWidth" :label-width="config.labelWidth || labelWidth"
@change="changeHandler" @change="changeHandler"
></m-form-container> ></Container>
</template> </template>
</div> </div>
</el-card> </TMagicCard>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { computed, defineComponent, inject, PropType, ref } from 'vue'; import { computed, inject, ref } from 'vue';
import { CaretBottom, CaretRight } from '@element-plus/icons-vue'; import { CaretBottom, CaretRight } from '@element-plus/icons-vue';
import { TMagicCard, TMagicIcon } from '@tmagic/design';
import { FormState, PanelConfig } from '../schema'; import { FormState, PanelConfig } from '../schema';
import { filterFunction } from '../utils/form'; import { filterFunction } from '../utils/form';
export default defineComponent({ import Container from './Container.vue';
name: 'm-form-panel',
components: { CaretBottom, CaretRight }, const props = defineProps<{
model: any;
config: PanelConfig;
name: string;
labelWidth?: string;
prop?: string;
size?: string;
}>();
props: { const emit = defineEmits(['change']);
labelWidth: String,
model: { const mForm = inject<FormState | undefined>('mForm');
type: Object,
default: () => ({}),
},
config: { const expand = ref(props.config.expand !== false);
type: Object as PropType<PanelConfig>,
default: () => ({}),
},
prop: String, const items = computed(() => props.config.items);
size: String, const filter = (config: any) => filterFunction(mForm, config, props);
name: String, const changeHandler = () => emit('change', props.model);
},
emits: ['change'],
setup(props, { emit }) {
const mForm = inject<FormState | undefined>('mForm');
const expand = ref(props.config.expand !== false);
const items = computed(() => props.config.items);
const filter = (config: any) => filterFunction(mForm, config, props);
const changeHandler = () => emit('change', props.model);
return {
mForm,
expand,
items,
filter,
changeHandler,
};
},
});
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-row :gutter="10"> <TMagicRow :gutter="10">
<Col <Col
v-for="(col, index) in config.items" v-for="(col, index) in config.items"
:key="col[mForm?.keyProp || '__key'] ?? index" :key="col[mForm?.keyProp || '__key'] ?? index"
@ -12,53 +12,31 @@
:size="size" :size="size"
@change="changeHandler" @change="changeHandler"
/> />
</el-row> </TMagicRow>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { defineComponent, inject, PropType } from 'vue'; import { inject } from 'vue';
import { TMagicRow } from '@tmagic/design';
import { FormState, RowConfig } from '../schema'; import { FormState, RowConfig } from '../schema';
import Col from './Col.vue'; import Col from './Col.vue';
export default defineComponent({ const props = defineProps<{
name: 'm-form-row', model: any;
config: RowConfig;
name: string;
labelWidth?: string;
prop?: string;
size?: string;
expandMore?: boolean;
}>();
components: { Col }, const emit = defineEmits(['change']);
props: { const mForm = inject<FormState | undefined>('mForm');
labelWidth: String,
expandMore: Boolean,
model: { const changeHandler = () => emit('change', props.name ? props.model[props.name] : props.model);
type: Object,
default: () => ({}),
},
config: {
type: Object as PropType<RowConfig>,
default: () => ({}),
},
prop: String,
name: String,
size: String,
},
emits: ['change'],
setup(props, { emit }) {
const mForm = inject<FormState | undefined>('mForm');
const changeHandler = () => emit('change', props.name ? props.model[props.name] : props.model);
return {
mForm,
changeHandler,
};
},
});
</script> </script>

View File

@ -1,82 +1,70 @@
<template> <template>
<div> <div>
<el-steps :active="active" align-center :space="config.space"> <TMagicSteps :active="active" align-center :space="config.space">
<el-step <TMagicStep
v-for="(item, index) in config.items" v-for="(item, index) in config.items"
:key="item.__key" :key="item.__key"
:title="item.title" :title="item.title"
:active="active" :active="active"
@click="stepClick(index)" @click="stepClick(index)"
></el-step> ></TMagicStep>
</el-steps> </TMagicSteps>
<template v-for="(step, index) in config.items"> <template v-for="(step, index) in config.items">
<template v-for="item in step.items"> <template v-for="item in step.items">
<m-form-container <Container
v-if="item" v-if="item"
v-show="active - 1 === index" v-show="active - 1 === index"
:key="item[mForm?.keyProp || '__key']" :key="item[mForm?.keyProp || '__key']"
:config="item" :config="item"
:model="step.name ? model[step.name] : model" :model="step.name ? model[step.name] : model"
:prop="step.name" :prop="`${step.name}`"
:size="size" :size="size"
:label-width="config.labelWidth || labelWidth" :label-width="config.labelWidth || labelWidth"
@change="changeHandler" @change="changeHandler"
></m-form-container> ></Container>
</template> </template>
</template> </template>
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { defineComponent, inject, PropType, ref, watchEffect } from 'vue'; import { inject, ref, watchEffect } from 'vue';
import { TMagicStep, TMagicSteps } from '@tmagic/design';
import { FormState, StepConfig } from '../schema'; import { FormState, StepConfig } from '../schema';
export default defineComponent({ import Container from './Container.vue';
name: 'm-form-step',
props: { const props = withDefaults(
model: { defineProps<{
type: Object, model: any;
default: () => ({}), config: StepConfig;
}, stepActive?: number;
labelWidth?: string;
config: { size?: string;
type: Object as PropType<StepConfig>, }>(),
default: () => ({}), {
}, stepActive: 1,
stepActive: {
type: Number,
default: () => 1,
},
size: String,
labelWidth: String,
}, },
);
emits: ['change'], const emit = defineEmits(['change']);
setup(props, { emit }) { const mForm = inject<FormState | undefined>('mForm');
const mForm = inject<FormState | undefined>('mForm'); const active = ref(1);
const active = ref(1);
watchEffect(() => { watchEffect(() => {
active.value = props.stepActive; active.value = props.stepActive;
});
const stepClick = (index: number) => {
active.value = index + 1;
mForm?.$emit('update:stepActive', active.value);
};
const changeHandler = () => {
emit('change', props.model);
};
return { mForm, active, stepClick, changeHandler };
},
}); });
const stepClick = (index: number) => {
active.value = index + 1;
mForm?.$emit('update:stepActive', active.value);
};
const changeHandler = () => {
emit('change', props.model);
};
</script> </script>

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
<template> <template>
<el-tabs <TMagicTabs
v-model="activeTabName" v-model="activeTabName"
:class="config.dynamic ? 'magic-form-dynamic-tab' : 'magic-form-tab'" :class="config.dynamic ? 'magic-form-dynamic-tab' : 'magic-form-tab'"
:type="config.tabType" :type="config.tabType"
@ -10,14 +10,14 @@
@tab-remove="onTabRemove" @tab-remove="onTabRemove"
> >
<template v-for="(tab, tabIndex) in tabs"> <template v-for="(tab, tabIndex) in tabs">
<el-tab-pane <TMagicTabPane
v-if="display(tab.display) && tabItems(tab).length" v-if="display(tab.display) && tabItems(tab).length"
:key="tab[mForm?.keyProp || '__key'] ?? tabIndex" :key="tab[mForm?.keyProp || '__key'] ?? tabIndex"
:name="filter(tab.status) || tabIndex.toString()" :name="filter(tab.status) || tabIndex.toString()"
:label="filter(tab.title)" :label="filter(tab.title)"
:lazy="tab.lazy || false" :lazy="tab.lazy || false"
> >
<m-form-container <Container
v-for="item in tabItems(tab)" v-for="item in tabItems(tab)"
:key="item[mForm?.keyProp || '__key']" :key="item[mForm?.keyProp || '__key']"
:config="item" :config="item"
@ -35,18 +35,22 @@
:label-width="tab.labelWidth || labelWidth" :label-width="tab.labelWidth || labelWidth"
:expand-more="expandMore" :expand-more="expandMore"
@change="changeHandler" @change="changeHandler"
></m-form-container> ></Container>
</el-tab-pane> </TMagicTabPane>
</template> </template>
</el-tabs> </TMagicTabs>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { computed, defineComponent, inject, PropType, ref, watchEffect } from 'vue'; import { computed, inject, ref, watchEffect } from 'vue';
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
import { FormState, FormValue, TabConfig, TabPaneConfig } from '../schema'; import { TMagicTabPane, TMagicTabs } from '@tmagic/design';
import { display, filterFunction } from '../utils/form';
import { FormState, TabConfig, TabPaneConfig } from '../schema';
import { display as displayFunc, filterFunction } from '../utils/form';
import Container from './Container.vue';
const getActive = (mForm: FormState | undefined, props: any, activeTabName: string) => { const getActive = (mForm: FormState | undefined, props: any, activeTabName: string) => {
const { config, model, prop } = props; const { config, model, prop } = props;
@ -59,7 +63,7 @@ const getActive = (mForm: FormState | undefined, props: any, activeTabName: stri
return '0'; return '0';
}; };
const tabClickHandler = (mForm: FormState | undefined, tab: any, props: any) => { const tabClick = (mForm: FormState | undefined, tab: any, props: any) => {
const { config, model, prop } = props; const { config, model, prop } = props;
// vue2element-ui // vue2element-ui
@ -75,123 +79,90 @@ const tabClickHandler = (mForm: FormState | undefined, tab: any, props: any) =>
} }
}; };
const Tab = defineComponent({ const props = defineProps<{
name: 'm-form-tab', model: any;
config: TabConfig;
name: string;
size?: string;
labelWidth?: string;
prop?: string;
expandMore?: boolean;
}>();
props: { const emit = defineEmits(['change']);
labelWidth: String,
expandMore: Boolean,
model: { const mForm = inject<FormState | undefined>('mForm');
type: Object, const activeTabName = ref(getActive(mForm, props, ''));
default: () => ({}),
},
config: { const tabs = computed(() => {
type: Object as PropType<TabConfig>, if (props.config.dynamic) {
default: () => ({}), if (!props.config.name) throw new Error('dynamic tab 必须配置name');
}, return props.model[props.config.name] || [];
}
prop: String, return props.config.items;
name: String,
size: String,
},
emits: {
change(values: FormValue) {
return values;
},
},
setup(props, { emit }) {
const mForm = inject<FormState | undefined>('mForm');
const activeTabName = ref(getActive(mForm, props, ''));
const tabs = computed(() => {
if (props.config.dynamic) {
if (!props.config.name) throw new Error('dynamic tab 必须配置name');
return props.model[props.config.name] || [];
}
return props.config.items;
});
const filter = (config: any) => filterFunction(mForm, config, props);
watchEffect(() => {
if (typeof props.config.activeChange === 'function') {
props.config.activeChange(mForm, activeTabName.value, {
model: props.model,
prop: props.prop,
});
}
});
return {
mForm,
activeTabName,
tabs,
filter,
tabItems: (tab: TabPaneConfig) => (props.config.dynamic ? props.config.items : tab.items),
tabClickHandler: (tab: any) => tabClickHandler(mForm, tab, props),
onTabAdd: () => {
if (!props.config.name) throw new Error('dynamic tab 必须配置name');
if (typeof props.config.onTabAdd === 'function') {
props.config.onTabAdd(mForm, {
model: props.model,
prop: props.prop,
config: props.config,
});
} else if (tabs.value.length > 0) {
const newObj = cloneDeep(tabs.value[0]);
newObj.title = `标签${tabs.value.length + 1}`;
props.model[props.config.name].push(newObj);
}
emit('change', props.model);
mForm?.$emit('field-change', props.prop, props.model[props.config.name]);
},
onTabRemove: (tabName: string) => {
if (!props.config.name) throw new Error('dynamic tab 必须配置name');
if (typeof props.config.onTabRemove === 'function') {
props.config.onTabRemove(mForm, tabName, {
model: props.model,
prop: props.prop,
config: props.config,
});
} else {
props.model[props.config.name].splice(+tabName, 1);
//
if (tabName < activeTabName.value || activeTabName.value >= props.model[props.config.name].length) {
activeTabName.value = (+activeTabName.value - 1).toString();
tabClickHandler(mForm, { name: activeTabName.value }, props);
}
}
emit('change', props.model);
mForm?.$emit('field-change', props.prop, props.model[props.config.name]);
},
display: (displayConfig: any) => display(mForm, displayConfig, props),
changeHandler: () => {
emit('change', props.model);
if (typeof props.config.onChange === 'function') {
props.config.onChange(mForm, { model: props.model, prop: props.prop, config: props.config });
}
},
};
},
}); });
export default Tab; const filter = (config: any) => filterFunction(mForm, config, props);
watchEffect(() => {
if (typeof props.config.activeChange === 'function') {
props.config.activeChange(mForm, activeTabName.value, {
model: props.model,
prop: props.prop,
});
}
});
const tabItems = (tab: TabPaneConfig) => (props.config.dynamic ? props.config.items : tab.items);
const tabClickHandler = (tab: any) => tabClick(mForm, tab, props);
const onTabAdd = () => {
if (!props.config.name) throw new Error('dynamic tab 必须配置name');
if (typeof props.config.onTabAdd === 'function') {
props.config.onTabAdd(mForm, {
model: props.model,
prop: props.prop,
config: props.config,
});
} else if (tabs.value.length > 0) {
const newObj = cloneDeep(tabs.value[0]);
newObj.title = `标签${tabs.value.length + 1}`;
props.model[props.config.name].push(newObj);
}
emit('change', props.model);
mForm?.$emit('field-change', props.prop, props.model[props.config.name]);
};
const onTabRemove = (tabName: string) => {
if (!props.config.name) throw new Error('dynamic tab 必须配置name');
if (typeof props.config.onTabRemove === 'function') {
props.config.onTabRemove(mForm, tabName, {
model: props.model,
prop: props.prop,
config: props.config,
});
} else {
props.model[props.config.name].splice(+tabName, 1);
//
if (tabName < activeTabName.value || activeTabName.value >= props.model[props.config.name].length) {
activeTabName.value = (+activeTabName.value - 1).toString();
tabClick(mForm, { name: activeTabName.value }, props);
}
}
emit('change', props.model);
mForm?.$emit('field-change', props.prop, props.model[props.config.name]);
};
const display = (displayConfig: any) => displayFunc(mForm, displayConfig, props);
const changeHandler = () => {
emit('change', props.model);
if (typeof props.config.onChange === 'function') {
props.config.onChange(mForm, { model: props.model, prop: props.prop, config: props.config });
}
};
</script> </script>

View File

@ -1,146 +1,98 @@
<template> <template>
<div class="m-cascader" style="width: 100%"> <TMagicCascader
<el-cascader v-model="model[name]"
v-model="model[name]" ref="tMagicCascader"
ref="cascader" style="width: 100%"
style="width: 100%" clearable
clearable filterable
filterable :size="size"
:size="size" :placeholder="config.placeholder"
:placeholder="config.placeholder" :disabled="disabled"
:disabled="disabled" :options="options"
:options="options" :props="{ multiple: config.multiple }"
:props="{ multiple: config.multiple }" @change="changeHandler"
@change="changeHandler" ></TMagicCascader>
></el-cascader>
</div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { import { inject, ref, watchEffect } from 'vue';
ComponentInternalInstance,
computed, import { TMagicCascader } from '@tmagic/design';
defineComponent,
getCurrentInstance,
inject,
PropType,
ref,
watchEffect,
} from 'vue';
import { CascaderConfig, FormState } from '../schema'; import { CascaderConfig, FormState } from '../schema';
import { getConfig } from '../utils/config'; import { getConfig } from '../utils/config';
import fieldProps from '../utils/fieldProps';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';
export default defineComponent({ const props = defineProps<{
name: 'm-fields-cascader', config: CascaderConfig;
model: any;
initValues?: any;
values?: any;
name: string;
prop: string;
disabled?: boolean;
size: 'mini' | 'small' | 'medium';
}>();
props: { const emit = defineEmits(['change']);
...fieldProps,
config: {
type: Object as PropType<CascaderConfig>,
required: true,
},
},
emits: ['change'], const mForm = inject<FormState | null>('mForm');
setup(props, { emit }) { useAddField(props.prop);
const mForm = inject<FormState | null>('mForm');
const vm = getCurrentInstance() as ComponentInternalInstance;
useAddField(props.prop); const requestFunc = getConfig('request') as Function;
const requestFunc = getConfig('request') as Function; const tMagicCascader = ref<InstanceType<typeof TMagicCascader>>();
const cascader = ref<any>(); const options = Array.isArray(props.config.options) ? ref(props.config.options) : ref([]);
const dialog = ref<any>(); const remoteData = ref<any>(null);
const options = Array.isArray(props.config.options) ? ref(props.config.options) : ref([]); const setRemoteOptions = async function () {
const remoteData = ref<any>(null); const { config } = props;
const { option } = config;
if (!option) return;
let { body } = option;
const setRemoteOptions = async function () { const postOptions: Record<string, any> = {
const { config } = props; url: option.url,
const { option } = config; cache: option.cache,
if (!option) return; timeout: option.timeout,
let { body } = option; data: {},
};
const postOptions: Record<string, any> = { if (body && mForm) {
url: option.url, if (typeof body === 'function' && props.model && mForm) {
cache: option.cache, body = body(mForm, {
timeout: option.timeout, model: props.model,
data: {}, formValue: mForm.values,
}; formValues: mForm.values,
config: props.config,
if (body && mForm) { });
if (typeof body === 'function' && props.model && mForm) {
body = body(mForm, {
model: props.model,
formValue: mForm.values,
formValues: mForm.values,
config: props.config,
});
}
postOptions.data = body;
}
const res = await requestFunc(postOptions);
remoteData.value = res[option.root];
if (remoteData.value && typeof option?.item === 'function') {
options.value = option.item(res[option.root]);
}
};
//
if (typeof props.config.options === 'function' && props.model && mForm) {
watchEffect(
() =>
(options.value = (props.config.options as Function)(vm, { model: props.model, formValues: mForm.values })),
);
} else if (!props.config.options || !props.config.options.length || props.config.remote) {
Promise.resolve(setRemoteOptions());
} }
postOptions.data = body;
}
const action = computed(() => { const res = await requestFunc(postOptions);
if (props.config.add?.action.method === 'post') {
return (options: any) =>
requestFunc({
...props.config?.add?.action.body,
...options,
});
}
return null;
});
return { remoteData.value = res[option.root];
options, if (remoteData.value && typeof option?.item === 'function') {
remoteData, options.value = option.item(res[option.root]);
addButtonStyle: { }
top: 0, };
left: 0,
width: 'auto', //
}, if (typeof props.config.options === 'function' && props.model && mForm) {
dialogVisible: false, watchEffect(
cascader, () => (options.value = (props.config.options as Function)(mForm, { model: props.model, formValues: mForm.values })),
dialog, );
action, } else if (!props.config.options || !props.config.options.length || props.config.remote) {
setRemoteOptions, Promise.resolve(setRemoteOptions());
changeHandler: (value: any) => { }
if (!cascader.value) return;
cascader.value.query = ''; const changeHandler = (value: any) => {
cascader.value.previousQuery = null; if (!tMagicCascader.value) return;
emit('change', value); tMagicCascader.value.setQuery('');
}, tMagicCascader.value.setPreviousQuery(null);
addHandler: () => { emit('change', value);
if (!dialog.value) return; };
dialog.value.dialogVisible = true;
},
editAfterAction: () => {
setRemoteOptions();
},
};
},
});
</script> </script>

View File

@ -1,67 +1,63 @@
<template> <template>
<el-checkbox <TMagicCheckbox
v-model="model[name]" v-model="model[name]"
:size="size" :size="size"
:trueLabel="activeValue" :trueLabel="activeValue"
:falseLabel="inactiveValue" :falseLabel="inactiveValue"
:disabled="disabled" :disabled="disabled"
:label="config.text"
@change="changeHandler" @change="changeHandler"
></el-checkbox> >{{ config.text }}</TMagicCheckbox
>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { computed, defineComponent, PropType } from 'vue'; import { computed } from 'vue';
import { TMagicCheckbox } from '@tmagic/design';
import { CheckboxConfig } from '../schema'; import { CheckboxConfig } from '../schema';
import fieldProps from '../utils/fieldProps';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';
export default defineComponent({ const props = defineProps<{
name: 'm-fields-checkbox', config: CheckboxConfig;
model: any;
initValues?: any;
values?: any;
name: string;
prop: string;
disabled?: boolean;
size: 'mini' | 'small' | 'medium';
}>();
props: { const emit = defineEmits(['change']);
...fieldProps,
config: {
type: Object as PropType<CheckboxConfig>,
required: true,
},
},
emits: ['change', 'input'], useAddField(props.prop);
setup(props, { emit }) { const activeValue = computed(() => {
useAddField(props.prop); if (typeof props.config.activeValue === 'undefined') {
if (props.config.filter === 'number') {
return 1;
}
} else {
return props.config.activeValue;
}
return { return undefined;
activeValue: computed(() => {
if (typeof props.config.activeValue === 'undefined') {
if (props.config.filter === 'number') {
return 1;
}
} else {
return props.config.activeValue;
}
return undefined;
}),
inactiveValue: computed(() => {
if (typeof props.config.inactiveValue === 'undefined') {
if (props.config.filter === 'number') {
return 0;
}
} else {
return props.config.inactiveValue;
}
return undefined;
}),
changeHandler(value: number | boolean) {
emit('change', value);
},
};
},
}); });
const inactiveValue = computed(() => {
if (typeof props.config.inactiveValue === 'undefined') {
if (props.config.filter === 'number') {
return 0;
}
} else {
return props.config.inactiveValue;
}
return undefined;
});
const changeHandler = (value: number | boolean) => {
emit('change', value);
};
</script> </script>

View File

@ -1,44 +1,42 @@
<template> <template>
<el-checkbox-group v-model="model[name]" :size="size" :disabled="disabled" @change="changeHandler"> <TMagicCheckboxGroup v-model="model[name]" :size="size" :disabled="disabled" @change="changeHandler">
<el-checkbox v-for="option in config.options" :label="option.value" :key="option.value" <TMagicCheckbox
v-for="option in config.options"
:label="option.value"
:key="option.value"
:disabled="option.disabled"
>{{ option.text }} >{{ option.text }}
</el-checkbox> </TMagicCheckbox>
</el-checkbox-group> </TMagicCheckboxGroup>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent, PropType } from 'vue'; import { TMagicCheckbox, TMagicCheckboxGroup } from '@tmagic/design';
import { CheckboxGroupConfig } from '../schema'; import { CheckboxGroupConfig } from '../schema';
import fieldProps from '../utils/fieldProps';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';
export default defineComponent({ const props = defineProps<{
name: 'm-fields-checkbox-group', config: CheckboxGroupConfig;
model: any;
initValues?: any;
values?: any;
name: string;
prop: string;
disabled?: boolean;
size: 'mini' | 'small' | 'medium';
}>();
props: { const emit = defineEmits(['change']);
...fieldProps,
config: {
type: Object as PropType<CheckboxGroupConfig>,
required: true,
},
},
emits: ['change'], useAddField(props.prop);
setup(props, { emit }) { //
useAddField(props.prop); if (props.model && !props.model[props.name]) {
props.model[props.name] = [];
}
// const changeHandler = (v: Array<string | number | boolean>) => {
if (props.model && !props.model[props.name]) { emit('change', v);
// eslint-disable-next-line no-param-reassign };
props.model[props.name] = [];
}
return {
changeHandler: (v: Array<string | number | boolean>) => {
emit('change', v);
},
};
},
});
</script> </script>

View File

@ -1,14 +1,16 @@
<template> <template>
<el-color-picker <TMagicColorPicker
v-model="model[name]" v-model="model[name]"
:size="size" :size="size"
:disabled="disabled" :disabled="disabled"
:showAlpha="true" :showAlpha="true"
@change="changeHandler" @change="changeHandler"
></el-color-picker> ></TMagicColorPicker>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { TMagicColorPicker } from '@tmagic/design';
import { ColorPickConfig } from '../schema'; import { ColorPickConfig } from '../schema';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';

View File

@ -1,5 +1,5 @@
<template> <template>
<el-date-picker <TMagicDatePicker
v-model="model[name]" v-model="model[name]"
type="date" type="date"
:size="size" :size="size"
@ -8,40 +8,34 @@
:format="config.format" :format="config.format"
:value-format="config.format || 'YYYY-MM-DD HH:mm:ss'" :value-format="config.format || 'YYYY-MM-DD HH:mm:ss'"
@change="changeHandler" @change="changeHandler"
></el-date-picker> ></TMagicDatePicker>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent, PropType } from 'vue'; import { TMagicDatePicker } from '@tmagic/design';
import { datetimeFormatter } from '@tmagic/utils'; import { datetimeFormatter } from '@tmagic/utils';
import { DateConfig } from '../schema'; import { DateConfig } from '../schema';
import fieldProps from '../utils/fieldProps';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';
export default defineComponent({ const props = defineProps<{
name: 'm-fields-date', config: DateConfig;
model: any;
initValues?: any;
values?: any;
name: string;
prop: string;
disabled?: boolean;
size: 'mini' | 'small' | 'medium';
}>();
props: { const emit = defineEmits(['change']);
...fieldProps,
config: {
type: Object as PropType<DateConfig>,
required: true,
},
},
emits: ['change', 'input'], useAddField(props.prop);
setup(props, { emit }) { props.model[props.name] = datetimeFormatter(props.model[props.name], '');
useAddField(props.prop);
props.model[props.name] = datetimeFormatter(props.model[props.name], ''); const changeHandler = (v: string) => {
return { emit('change', v);
changeHandler(v: string) { };
emit('change', v);
},
};
},
});
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-date-picker <TMagicDatePicker
v-model="model[name]" v-model="model[name]"
popper-class="magic-datetime-picker-popper" popper-class="magic-datetime-picker-popper"
type="datetime" type="datetime"
@ -10,49 +10,41 @@
:value-format="config.valueFormat || 'YYYY-MM-DD HH:mm:ss'" :value-format="config.valueFormat || 'YYYY-MM-DD HH:mm:ss'"
:default-time="config.defaultTime" :default-time="config.defaultTime"
@change="changeHandler" @change="changeHandler"
></el-date-picker> ></TMagicDatePicker>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent, PropType } from 'vue'; import { TMagicDatePicker } from '@tmagic/design';
import { datetimeFormatter } from '@tmagic/utils'; import { datetimeFormatter } from '@tmagic/utils';
import { DateTimeConfig } from '../schema'; import { DateTimeConfig } from '../schema';
import fieldProps from '../utils/fieldProps';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';
export default defineComponent({ const props = defineProps<{
name: 'm-fields-datetime', config: DateTimeConfig;
model: any;
initValues?: any;
values?: any;
name: string;
prop: string;
disabled?: boolean;
size: 'mini' | 'small' | 'medium';
}>();
props: { const emit = defineEmits(['change']);
...fieldProps,
config: {
type: Object as PropType<DateTimeConfig>,
required: true,
},
},
emits: ['change'], useAddField(props.prop);
setup(props, { emit }) { const value = props.model?.[props.name].toString();
useAddField(props.prop); if (props.model) {
if (value === 'Invalid Date') {
props.model[props.name] = '';
} else {
props.model[props.name] = datetimeFormatter(props.model[props.name], '', props.config.valueFormat);
}
}
const value = props.model?.[props.name].toString(); const changeHandler = (v: string) => {
if (props.model) { emit('change', v);
if (value === 'Invalid Date') { };
props.model[props.name] = '';
} else {
props.model[props.name] = datetimeFormatter(props.model[props.name], '', props.config.valueFormat);
}
}
return {
value,
changeHandler: (v: Date) => {
emit('change', v);
},
};
},
});
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-date-picker <TMagicDatePicker
v-model="value" v-model="value"
type="datetimerange" type="datetimerange"
range-separator="-" range-separator="-"
@ -10,12 +10,13 @@
:disabled="disabled" :disabled="disabled"
:default-time="config.defaultTime" :default-time="config.defaultTime"
@change="changeHandler" @change="changeHandler"
></el-date-picker> ></TMagicDatePicker>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { TMagicDatePicker } from '@tmagic/design';
import { datetimeFormatter } from '@tmagic/utils'; import { datetimeFormatter } from '@tmagic/utils';
import { DaterangeConfig } from '../schema'; import { DaterangeConfig } from '../schema';

View File

@ -1,18 +1,18 @@
<template> <template>
<div class="m-fields-dynamic-field"> <div class="m-fields-dynamic-field">
<el-form size="small"> <TMagicForm size="small">
<el-form-item v-for="key in Object.keys(fieldMap.value)" :key="key" :label="fieldLabelMap.value[key]"> <TMagicFormItem v-for="key in Object.keys(fieldMap.value)" :key="key" :label="fieldLabelMap.value[key]">
<el-input <TMagicInput
v-model="fieldMap.value[key]" v-model="fieldMap.value[key]"
:placeholder="fieldLabelMap.value[key]" :placeholder="fieldLabelMap.value[key]"
@change="inputChangeHandler(key)" @change="inputChangeHandler(key)"
></el-input> ></TMagicInput>
</el-form-item> </TMagicFormItem>
</el-form> </TMagicForm>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
/** /**
* 动态表单目前只支持input类型字段 * 动态表单目前只支持input类型字段
* inputType: 'dynamic-field', * inputType: 'dynamic-field',
@ -23,87 +23,73 @@
* 特别注意field的上一级必须extensible: true才能保存未声明的字段 * 特别注意field的上一级必须extensible: true才能保存未声明的字段
*/ */
import { defineComponent, onBeforeUnmount, PropType, reactive, watch } from 'vue'; import { onBeforeUnmount, reactive, watch } from 'vue';
import { TMagicForm, TMagicFormItem, TMagicInput } from '@tmagic/design';
import { DynamicFieldConfig } from '../schema'; import { DynamicFieldConfig } from '../schema';
import { getConfig } from '../utils/config'; import { getConfig } from '../utils/config';
import fieldProps from '../utils/fieldProps';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';
export default defineComponent({ const props = defineProps<{
name: 'm-fields-dynamic-field', config: DynamicFieldConfig;
model: any;
initValues?: any;
values?: any;
name: string;
prop: string;
disabled?: boolean;
size: 'mini' | 'small' | 'medium';
}>();
props: { const emit = defineEmits(['change']);
...fieldProps,
config: {
type: Object as PropType<DynamicFieldConfig>,
required: true,
},
},
emits: ['change'], useAddField(props.prop);
setup(props, { emit }) { const request = getConfig('request') as Function;
useAddField(props.prop); const fieldMap = reactive<{ [key: string]: any }>({
value: {},
const request = getConfig('request') as Function;
const fieldMap = reactive<{ [key: string]: any }>({
value: {},
});
const fieldLabelMap = reactive<{ [key: string]: any }>({
value: {},
});
const changeFieldMap = async () => {
if (typeof props.config.returnFields !== 'function' || !props.model) return;
const fields = await props.config.returnFields(props.config, props.model, request);
fieldMap.value = {};
fieldLabelMap.value = {};
fields.forEach((v) => {
if (typeof v !== 'object' || v.name === undefined) return;
let oldVal = props.model?.[v.name] || '';
if (!oldVal && v.defaultValue !== undefined) {
oldVal = v.defaultValue;
emit('change', oldVal, v.name);
}
fieldMap.value[v.name] = oldVal;
fieldLabelMap.value[v.name] = v.label || '';
});
};
const unwatch = watch(
() => props.model?.[props.config.dynamicKey],
(val) => {
if (val !== '') {
changeFieldMap();
}
},
{
immediate: true,
},
);
onBeforeUnmount(() => {
if (typeof unwatch === 'function') {
unwatch();
}
});
return {
request,
fieldMap,
fieldLabelMap,
unwatch,
changeFieldMap,
inputChangeHandler: (key: string) => {
emit('change', fieldMap.value[key], key);
},
};
},
methods: {
init() {},
},
}); });
const fieldLabelMap = reactive<{ [key: string]: any }>({
value: {},
});
const changeFieldMap = async () => {
if (typeof props.config.returnFields !== 'function' || !props.model) return;
const fields = await props.config.returnFields(props.config, props.model, request);
fieldMap.value = {};
fieldLabelMap.value = {};
fields.forEach((v) => {
if (typeof v !== 'object' || v.name === undefined) return;
let oldVal = props.model?.[v.name] || '';
if (!oldVal && v.defaultValue !== undefined) {
oldVal = v.defaultValue;
emit('change', oldVal, v.name);
}
fieldMap.value[v.name] = oldVal;
fieldLabelMap.value[v.name] = v.label || '';
});
};
const unwatch = watch(
() => props.model?.[props.config.dynamicKey],
(val) => {
if (val !== '') {
changeFieldMap();
}
},
{
immediate: true,
},
);
onBeforeUnmount(() => {
if (typeof unwatch === 'function') {
unwatch();
}
});
const inputChangeHandler = (key: string) => {
emit('change', fieldMap.value[key], key);
};
</script> </script>

View File

@ -2,8 +2,8 @@
<a v-if="config.href && !disabled" target="_blank" :href="href" :style="config.css || {}">{{ displayText }}</a> <a v-if="config.href && !disabled" target="_blank" :href="href" :style="config.css || {}">{{ displayText }}</a>
<span v-else-if="config.href && disabled" :style="config.disabledCss || {}">{{ displayText }}</span> <span v-else-if="config.href && disabled" :style="config.disabledCss || {}">{{ displayText }}</span>
<div v-else class="m-fields-link"> <div v-else class="m-fields-link">
<el-button text type="primary" @click="editHandler">点击编辑</el-button> <TMagicButton :text="true" type="primary" @click="editHandler">点击编辑</TMagicButton>
<m-form-dialog <FormDialog
ref="editor" ref="editor"
:title="config.formTitle || '编辑扩展配置'" :title="config.formTitle || '编辑扩展配置'"
:width="config.formWidth" :width="config.formWidth"
@ -12,101 +12,80 @@
:parentValues="values" :parentValues="values"
:fullscreen="config.fullscreen" :fullscreen="config.fullscreen"
@submit="action" @submit="action"
></m-form-dialog> ></FormDialog>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { computed, defineComponent, inject, PropType, ref } from 'vue'; import { computed, inject, ref } from 'vue';
import { TMagicButton } from '@tmagic/design';
import FormDialog from '../FormDialog.vue'; import FormDialog from '../FormDialog.vue';
import { FormState, LinkConfig } from '../schema'; import { FormState, LinkConfig } from '../schema';
import fieldProps from '../utils/fieldProps';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';
export default defineComponent({ const props = defineProps<{
name: 'm-fields-link', config: LinkConfig;
model: any;
initValues?: any;
values?: any;
name: string;
prop: string;
disabled?: boolean;
size: 'mini' | 'small' | 'medium';
}>();
props: { const emit = defineEmits(['change']);
...fieldProps,
config: {
type: Object as PropType<LinkConfig>,
required: true,
},
},
emits: ['change'], useAddField(props.prop);
setup(props, { emit }) { const formValue = ref({});
useAddField(props.prop); const editor = ref<InstanceType<typeof FormDialog>>();
const mForm = inject<FormState | undefined>('mForm');
const formValue = ref({}); const href = computed(() => {
const editor = ref<InstanceType<typeof FormDialog>>(); if (typeof props.config.href === 'function' && props.model) {
const mForm = inject<FormState | undefined>('mForm'); return props.config.href(props.model);
}
const href = computed(() => { return props.config.href || props.model?.[props.name];
if (typeof props.config.href === 'function' && props.model) {
return props.config.href(props.model);
}
return props.config.href || props.model?.[props.name];
});
const init = () => {
formValue.value = props.model?.[props.name] || {};
};
return {
// ref
formValue,
editor,
// computed methods
href,
formConfig: computed(() => {
if (typeof props.config.form === 'function') {
return props.config.form(mForm, {
model: props.model || {},
values: props.values || {},
});
}
return props.config.form;
}),
disable: computed(() => {
if (typeof props.config.disabled !== 'undefined') {
return props.config.disabled;
}
return !href.value;
}),
displayText: computed(() => {
if (typeof props.config.displayText === 'function') {
return props.config.displayText(mForm, { model: props.model || {} });
}
if (props.config.displayText) {
return props.config.displayText;
}
return '跳转';
}),
// methods
init,
editHandler: () => {
init();
editor.value && (editor.value.dialogVisible = true);
},
action: (data: any) => {
if (props.model) {
props.model[props.name] = data;
formValue.value = data;
emit('change', props.model[props.name]);
}
editor.value && (editor.value.dialogVisible = false);
},
};
},
}); });
const init = () => {
formValue.value = props.model?.[props.name] || {};
};
const formConfig = computed(() => {
if (typeof props.config.form === 'function') {
return props.config.form(mForm, {
model: props.model || {},
values: props.values || {},
});
}
return props.config.form;
});
const displayText = computed(() => {
if (typeof props.config.displayText === 'function') {
return props.config.displayText(mForm, { model: props.model || {} });
}
if (props.config.displayText) {
return props.config.displayText;
}
return '跳转';
});
const editHandler = () => {
init();
editor.value && (editor.value.dialogVisible = true);
};
const action = (data: any) => {
if (props.model) {
props.model[props.name] = data;
formValue.value = data;
emit('change', props.model[props.name]);
}
editor.value && (editor.value.dialogVisible = false);
};
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-input-number <TMagicInputNumber
v-if="model" v-if="model"
v-model="model[name]" v-model="model[name]"
clearable clearable
@ -12,42 +12,40 @@
:disabled="disabled" :disabled="disabled"
@change="changeHandler" @change="changeHandler"
@input="inputHandler" @input="inputHandler"
></el-input-number> ></TMagicInputNumber>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent, inject, PropType } from 'vue'; import { inject } from 'vue';
import { TMagicInputNumber } from '@tmagic/design';
import { FormState, NumberConfig } from '../schema'; import { FormState, NumberConfig } from '../schema';
import fieldProps from '../utils/fieldProps';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';
export default defineComponent({
name: 'm-fields-number',
props: { const props = defineProps<{
...fieldProps, config: NumberConfig;
config: { model: any;
type: Object as PropType<NumberConfig>, initValues?: any;
required: true, values?: any;
}, name: string;
}, prop: string;
disabled?: boolean;
size: 'mini' | 'small' | 'medium';
}>();
emits: ['change', 'input'], const emit = defineEmits(['change', 'input']);
setup(props, { emit }) { useAddField(props.prop);
useAddField(props.prop);
const mForm = inject<FormState | null>('mForm'); const mForm = inject<FormState | null>('mForm');
return {
mForm, const changeHandler = (value: number) => {
changeHandler: (value: number) => { emit('change', value);
emit('change', value); };
},
inputHandler: (v: string) => { const inputHandler = (v: string) => {
emit('input', v); emit('input', v);
mForm?.$emit('field-input', props.prop, v); mForm?.$emit('field-input', props.prop, v);
}, };
};
},
});
</script> </script>

View File

@ -1,33 +1,33 @@
<template> <template>
<el-radio-group v-if="model" v-model="model[name]" :size="size" :disabled="disabled" @change="changeHandler"> <TMagicRadioGroup v-if="model" v-model="model[name]" :size="size" :disabled="disabled" @change="changeHandler">
<el-radio v-for="option in config.options" :label="option.value" :key="option.value">{{ option.text }}</el-radio> <TMagicRadio v-for="option in config.options" :label="option.value" :key="`${option.value}`">{{
</el-radio-group> option.text
}}</TMagicRadio>
</TMagicRadioGroup>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent } from 'vue'; import { TMagicRadio, TMagicRadioGroup } from '@tmagic/design';
import fieldProps from '../utils/fieldProps'; import { RadioGroupConfig } from '../schema';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';
export default defineComponent({ const props = defineProps<{
name: 'm-fields-radio-group', config: RadioGroupConfig;
model: any;
initValues?: any;
values?: any;
name: string;
prop: string;
disabled?: boolean;
size: 'mini' | 'small' | 'medium';
}>();
props: { const emit = defineEmits(['change']);
...fieldProps,
config: {
type: Object,
required: true,
},
},
emits: ['change'], const changeHandler = (value: number) => {
emit('change', value);
};
setup(props, { emit }) { useAddField(props.prop);
useAddField(props.prop);
return {
changeHandler: (v: string | number | boolean) => emit('change', v),
};
},
});
</script> </script>

View File

@ -1,10 +1,10 @@
<template> <template>
<el-select <TMagicSelect
v-if="model" v-if="model"
v-model="model[name]" v-model="model[name]"
v-loading="loading" v-loading="loading"
class="m-select" class="m-select"
ref="select" ref="tMagicSelect"
clearable clearable
filterable filterable
:popper-class="`m-select-popper ${popperClass}`" :popper-class="`m-select-popper ${popperClass}`"
@ -19,346 +19,330 @@
@change="changeHandler" @change="changeHandler"
@visible-change="visibleHandler" @visible-change="visibleHandler"
> >
<template v-if="config.group"><select-option-groups :options="groupOptions"></select-option-groups></template> <template v-if="config.group"><SelectOptionGroups :options="groupOptions"></SelectOptionGroups></template>
<template v-else><select-options :options="options"></select-options></template> <template v-else><SelectOptions :options="itemOptions"></SelectOptions></template>
<div v-loading="true" v-if="moreLoadingVisible"></div> <div v-loading="true" v-if="moreLoadingVisible"></div>
</el-select> </TMagicSelect>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent, inject, onBeforeMount, onMounted, PropType, Ref, ref, watchEffect } from 'vue'; import { inject, nextTick, onBeforeMount, onMounted, Ref, ref, watchEffect } from 'vue';
import { TMagicSelect } from '@tmagic/design';
import { FormState, SelectConfig, SelectGroupOption, SelectOption } from '../schema'; import { FormState, SelectConfig, SelectGroupOption, SelectOption } from '../schema';
import { getConfig } from '../utils/config'; import { getConfig } from '../utils/config';
import fieldProps from '../utils/fieldProps';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';
import SelectOptionGroups from './SelectOptionGroups.vue'; import SelectOptionGroups from './SelectOptionGroups.vue';
import SelectOptions from './SelectOptions.vue'; import SelectOptions from './SelectOptions.vue';
export default defineComponent({ const props = defineProps<{
name: 'm-fields-select', config: SelectConfig;
model: any;
initValues?: any;
values?: any;
name: string;
prop: string;
disabled?: boolean;
size: 'mini' | 'small' | 'medium';
}>();
components: { SelectOptions, SelectOptionGroups }, const emit = defineEmits(['change']);
props: { if (!props.model) throw new Error('不能没有model');
...fieldProps, useAddField(props.prop);
config: {
type: Object as PropType<SelectConfig>,
required: true,
},
},
emits: ['change'], const tMagicSelect = ref<InstanceType<typeof TMagicSelect>>();
const mForm = inject<FormState | undefined>('mForm');
const options = ref<SelectOption[] | SelectGroupOption[]>([]);
const localOptions = ref<SelectOption[] | SelectGroupOption[]>([]);
const loading = ref(false);
const moreLoadingVisible = ref(false);
const total = ref(0);
const pgIndex = ref(0);
const pgSize = ref(20);
const query = ref('');
const remoteData = ref<any[]>([]);
const remote = ref(true);
setup(props, { emit }) { const equalValue = (value: any, v: any): boolean => {
if (!props.model) throw new Error('不能没有model'); if (typeof v === 'object') {
useAddField(props.prop); const key = props.config.valueKey || 'value';
return v[key] === value[key];
}
const select = ref<any>(); return value === v;
const mForm = inject<FormState | undefined>('mForm'); };
const options = ref<SelectOption[] | SelectGroupOption[]>([]);
const localOptions = ref<SelectOption[] | SelectGroupOption[]>([]);
const loading = ref(false);
const moreLoadingVisible = ref(false);
const total = ref(0);
const pgIndex = ref(0);
const pgSize = ref(20);
const query = ref('');
const remoteData = ref<any[]>([]);
const remote = ref(true);
const equalValue = (value: any, v: any): boolean => { const mapOptions = (data: any[]) => {
if (typeof v === 'object') { const { option } = props.config;
const key = props.config.valueKey || 'value'; const { text } = option;
return v[key] === value[key]; const { value } = option;
}
return value === v; return data.map((item) => ({
}; text: typeof text === 'function' ? text(item) : item[text || 'text'],
value: typeof value === 'function' ? value(item) : item[value || 'value'],
}));
};
const mapOptions = (data: any[]) => { const getOptions = async () => {
const { option } = props.config; if (!props.model) return [];
const { text } = option;
const { value } = option;
return data.map((item) => ({ if (localOptions.value.length) {
text: typeof text === 'function' ? text(item) : item[text || 'text'], return localOptions.value;
value: typeof value === 'function' ? value(item) : item[value || 'value'], }
}));
};
const getOptions = async () => { loading.value = true;
if (!props.model) return [];
if (localOptions.value.length) { let items: SelectOption[] | SelectGroupOption[] = [];
return localOptions.value;
}
loading.value = true; const { config } = props;
const { option } = config;
let { body } = option;
let items: SelectOption[] | SelectGroupOption[] = []; let postOptions: Record<string, any> = {
method: option.method || 'POST',
url: option.url,
cache: option.cache,
timeout: option.timeout,
mode: option.mode,
headers: option.headers || {},
json: option.json || false,
};
const { config } = props; if (body) {
const { option } = config; if (typeof body === 'function') {
let { body } = option; body = body(mForm, {
model: props.model,
let postOptions: Record<string, any> = { formValue: mForm?.values,
method: option.method || 'POST', formValues: mForm?.values,
url: option.url, config: props.config,
cache: option.cache, }) as Record<string, any>;
timeout: option.timeout,
mode: option.mode,
headers: option.headers || {},
json: option.json || false,
};
if (body) {
if (typeof body === 'function') {
body = body(mForm, {
model: props.model,
formValue: mForm?.values,
formValues: mForm?.values,
config: props.config,
}) as Record<string, any>;
}
body.query = query.value;
body.pgSize = pgSize.value;
body.pgIndex = pgIndex.value;
postOptions.data = body;
}
const requestFuc = getConfig('request') as Function;
if (typeof option.beforeRequest === 'function') {
postOptions = option.beforeRequest(mForm, postOptions, {
model: props.model,
formValue: mForm?.values,
});
}
if (option.method?.toLocaleLowerCase() === 'jsonp') {
postOptions.jsonpCallback = option.jsonpCallback || 'callback';
}
let res = await requestFuc(postOptions);
if (typeof option.afterRequest === 'function') {
res = option.afterRequest(mForm, res, {
model: props.model,
formValue: mForm?.values,
formValues: mForm?.values,
config: props.config,
});
}
const optionsData = res[option.root];
if (res.total > 0) {
total.value = res.total;
}
remoteData.value = remoteData.value.concat(optionsData);
if (optionsData) {
if (typeof option.item === 'function') {
items = option.item(optionsData);
} else if (optionsData.map) {
items = mapOptions(optionsData);
}
}
loading.value = false;
//
const selectedOptions: SelectOption[] | SelectGroupOption[] = [];
if (props.config.multiple && props.model[props.name]) {
options.value.forEach((o: any) => {
const isInclude = props.model?.[props.name].includes(o.value);
if (isInclude && !(items as any[]).find((op: any) => op.value === o.value)) {
selectedOptions.push(o);
}
});
}
return pgIndex.value === 0 ? (selectedOptions as any[]).concat(items) : (options.value as any).concat(items);
};
const getInitLocalOption = async () => {
if (!props.model) return [];
const value = props.model[props.name];
const { config } = props;
localOptions.value = await getOptions();
remote.value = false;
if (config.group) {
if (config.multiple && value.findIndex) {
return (localOptions.value as SelectGroupOption[]).filter(
(group) => group.options.findIndex((item) => value.find((v: any) => equalValue(item.value, v)) > -1) > -1,
);
}
return (localOptions.value as SelectGroupOption[]).filter(
(group) => group.options.findIndex((item) => equalValue(item.value, value)) > -1,
);
}
if (config.multiple && value.findIndex) {
return (localOptions.value as any[]).filter(
(item) => value.findIndex((v: any) => equalValue(item.value, v)) > -1,
);
}
return (localOptions.value as any[]).filter((item) => equalValue(item.value, value));
};
const getInitOption = async () => {
if (!props.model) return [];
const { config } = props;
const { option } = config;
let options: SelectOption[] | SelectGroupOption[] = [];
let url = option.initUrl;
if (!url) {
return getInitLocalOption();
}
if (typeof url === 'function') {
url = await url(mForm, { model: props.model, formValue: mForm?.values });
}
const postOptions: Record<string, any> = {
method: option.method || 'POST',
url,
data: {
id: props.model[props.name],
},
mode: option.mode,
headers: option.headers || {},
json: option.json || false,
};
if (option.method?.toLocaleLowerCase() === 'jsonp') {
postOptions.jsonpCallback = option.jsonpCallback || 'callback';
}
const requestFuc = getConfig('request') as Function;
const res = await requestFuc(postOptions);
let initData = res[option.root];
if (initData) {
if (!Array.isArray(initData)) {
initData = [initData];
}
if (typeof option.item === 'function') {
options = option.item(initData);
} else if (initData.map) {
options = mapOptions(initData);
}
}
return options;
};
if (typeof props.config.options === 'function') {
watchEffect(() => {
typeof props.config.options === 'function' &&
Promise.resolve(
props.config.options(mForm, {
model: props.model,
prop: props.prop,
formValues: mForm?.values,
formValue: mForm?.values,
config: props.config,
}),
).then((data) => {
options.value = data;
});
});
} else if (Array.isArray(props.config.options)) {
watchEffect(() => {
options.value = props.config.options as SelectOption[] | SelectGroupOption[];
});
} else if (props.config.option) {
onBeforeMount(() => {
if (!props.model) return;
const v = props.model[props.name];
if (Array.isArray(v) ? v.length : typeof v !== 'undefined') {
getInitOption().then((data) => {
options.value = data;
});
}
});
} }
props.config.remote && body.query = query.value;
onMounted(() => { body.pgSize = pgSize.value;
select.value?.scrollbar.wrap$.addEventListener('scroll', async (e: Event) => { body.pgIndex = pgIndex.value;
const el = e.currentTarget as HTMLDivElement; postOptions.data = body;
if (moreLoadingVisible.value) { }
return;
} const requestFuc = getConfig('request') as Function;
if (el.scrollHeight - el.clientHeight - el.scrollTop > 1) {
return; if (typeof option.beforeRequest === 'function') {
} postOptions = option.beforeRequest(mForm, postOptions, {
if (total.value <= options.value.length) { model: props.model,
return; formValue: mForm?.values,
} });
moreLoadingVisible.value = true; }
pgIndex.value += 1;
options.value = await getOptions(); if (option.method?.toLocaleLowerCase() === 'jsonp') {
moreLoadingVisible.value = false; postOptions.jsonpCallback = option.jsonpCallback || 'callback';
}); }
let res = await requestFuc(postOptions);
if (typeof option.afterRequest === 'function') {
res = option.afterRequest(mForm, res, {
model: props.model,
formValue: mForm?.values,
formValues: mForm?.values,
config: props.config,
});
}
const optionsData = res[option.root];
if (res.total > 0) {
total.value = res.total;
}
remoteData.value = remoteData.value.concat(optionsData);
if (optionsData) {
if (typeof option.item === 'function') {
items = option.item(optionsData);
} else if (optionsData.map) {
items = mapOptions(optionsData);
}
}
loading.value = false;
//
const selectedOptions: SelectOption[] | SelectGroupOption[] = [];
if (props.config.multiple && props.model[props.name]) {
options.value.forEach((o: any) => {
const isInclude = props.model?.[props.name].includes(o.value);
if (isInclude && !(items as any[]).find((op: any) => op.value === o.value)) {
selectedOptions.push(o);
}
});
}
return pgIndex.value === 0 ? (selectedOptions as any[]).concat(items) : (options.value as any).concat(items);
};
const getInitLocalOption = async () => {
if (!props.model) return [];
const value = props.model[props.name];
const { config } = props;
localOptions.value = await getOptions();
remote.value = false;
if (config.group) {
if (config.multiple && value.findIndex) {
return (localOptions.value as SelectGroupOption[]).filter(
(group) => group.options.findIndex((item) => value.find((v: any) => equalValue(item.value, v)) > -1) > -1,
);
}
return (localOptions.value as SelectGroupOption[]).filter(
(group) => group.options.findIndex((item) => equalValue(item.value, value)) > -1,
);
}
if (config.multiple && value.findIndex) {
return (localOptions.value as any[]).filter((item) => value.findIndex((v: any) => equalValue(item.value, v)) > -1);
}
return (localOptions.value as any[]).filter((item) => equalValue(item.value, value));
};
const getInitOption = async () => {
if (!props.model) return [];
const { config } = props;
const { option } = config;
let options: SelectOption[] | SelectGroupOption[] = [];
let url = option.initUrl;
if (!url) {
return getInitLocalOption();
}
if (typeof url === 'function') {
url = await url(mForm, { model: props.model, formValue: mForm?.values });
}
const postOptions: Record<string, any> = {
method: option.method || 'POST',
url,
data: {
id: props.model[props.name],
},
mode: option.mode,
headers: option.headers || {},
json: option.json || false,
};
if (option.method?.toLocaleLowerCase() === 'jsonp') {
postOptions.jsonpCallback = option.jsonpCallback || 'callback';
}
const requestFuc = getConfig('request') as Function;
const res = await requestFuc(postOptions);
let initData = res[option.root];
if (initData) {
if (!Array.isArray(initData)) {
initData = [initData];
}
if (typeof option.item === 'function') {
options = option.item(initData);
} else if (initData.map) {
options = mapOptions(initData);
}
}
return options;
};
if (typeof props.config.options === 'function') {
watchEffect(() => {
typeof props.config.options === 'function' &&
Promise.resolve(
props.config.options(mForm, {
model: props.model,
prop: props.prop,
formValues: mForm?.values,
formValue: mForm?.values,
config: props.config,
}),
).then((data) => {
options.value = data;
}); });
});
} else if (Array.isArray(props.config.options)) {
watchEffect(() => {
options.value = props.config.options as SelectOption[] | SelectGroupOption[];
});
} else if (props.config.option) {
onBeforeMount(() => {
if (!props.model) return;
const v = props.model[props.name];
if (Array.isArray(v) ? v.length : typeof v !== 'undefined') {
getInitOption().then((data) => {
options.value = data;
});
}
});
}
return { props.config.remote &&
select, onMounted(async () => {
loading, await nextTick();
remote, tMagicSelect.value?.scrollbarWrap?.addEventListener('scroll', async (e: Event) => {
options: options as Ref<SelectOption[]>, const el = e.currentTarget as HTMLDivElement;
groupOptions: options as Ref<SelectGroupOption[]>, if (moreLoadingVisible.value) {
moreLoadingVisible, return;
popperClass: mForm?.popperClass, }
if (el.scrollHeight - el.clientHeight - el.scrollTop > 1) {
return;
}
if (total.value <= options.value.length) {
return;
}
moreLoadingVisible.value = true;
pgIndex.value += 1;
options.value = await getOptions();
moreLoadingVisible.value = false;
});
});
getOptions, const popperClass = mForm?.popperClass;
getRequestFuc() { const changeHandler = (value: any) => {
return getConfig('request'); emit('change', value);
}, };
changeHandler(value: any) { const visibleHandler = async (visible: boolean) => {
emit('change', value); if (!visible) return;
},
async visibleHandler(visible: boolean) { if (!props.config.remote) return;
if (!visible) return; if (query.value && tMagicSelect.value) {
tMagicSelect.value.setQuery(query.value);
tMagicSelect.value.setPreviousQuery(query.value);
tMagicSelect.value.setSelectedLabel(query.value);
} else if (options.value.length <= (props.config.multiple ? props.model?.[props.name].length : 1)) {
options.value = await getOptions();
}
};
if (!props.config.remote) return; const remoteMethod = async (q: string) => {
if (query.value && select.value) { if (!localOptions.value.length) {
select.value.query = query.value; query.value = q;
select.value.previousQuery = query.value; pgIndex.value = 0;
select.value.selectedLabel = query.value; options.value = await getOptions();
} else if (options.value.length <= (props.config.multiple ? props.model?.[props.name].length : 1)) { // el-select
options.value = await getOptions(); if (props.config.multiple)
} setTimeout(() => {
}, tMagicSelect.value?.setSelected();
}, 0);
}
};
async remoteMethod(q: string) { const itemOptions = options as Ref<SelectOption[]>;
if (!localOptions.value.length) { const groupOptions = options as Ref<SelectGroupOption[]>;
query.value = q;
pgIndex.value = 0;
options.value = await getOptions();
// el-select
if (props.config.multiple)
setTimeout(() => {
select.value?.setSelected();
}, 0);
}
},
};
},
});
</script> </script>

View File

@ -1,17 +1,19 @@
<template> <template>
<el-option-group v-for="(group, index) in options" :key="index" :label="group.label" :disabled="group.disabled"> <TMagicOptionGroup v-for="(group, index) in options" :key="index" :label="group.label" :disabled="group.disabled">
<el-option <TMagicOption
v-for="(item, index) in group.options" v-for="(item, index) in group.options"
:key="index" :key="index"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
:disabled="item.disabled" :disabled="item.disabled"
> >
</el-option> </TMagicOption>
</el-option-group> </TMagicOptionGroup>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { TMagicOption, TMagicOptionGroup } from '@tmagic/design';
import { SelectGroupOption } from '../schema'; import { SelectGroupOption } from '../schema';
defineProps<{ defineProps<{

View File

@ -1,14 +1,16 @@
<template> <template>
<el-option <TMagicOption
v-for="option in options" v-for="option in options"
:label="option.text" :label="option.text"
:value="option.value" :value="option.value"
:key="valueKey ? option.value[valueKey] : option.value" :key="valueKey ? option.value[valueKey] : option.value"
:disabled="option.disabled" :disabled="option.disabled"
></el-option> ></TMagicOption>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { TMagicOption } from '@tmagic/design';
import { SelectOption } from '../schema'; import { SelectOption } from '../schema';
defineProps<{ defineProps<{

View File

@ -1,65 +1,62 @@
<template> <template>
<el-switch <TMagicSwitch
v-if="model" v-model="model[name]"
v-model="model[n]"
:size="size" :size="size"
:activeValue="activeValue" :activeValue="activeValue"
:inactiveValue="inactiveValue" :inactiveValue="inactiveValue"
:disabled="disabled" :disabled="disabled"
@change="changeHandler" @change="changeHandler"
></el-switch> ></TMagicSwitch>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { computed, defineComponent, PropType } from 'vue'; import { computed } from 'vue';
import { TMagicSwitch } from '@tmagic/design';
import { SwitchConfig } from '../schema'; import { SwitchConfig } from '../schema';
import fieldProps from '../utils/fieldProps';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';
export default defineComponent({
name: 'm-fields-switch',
props: { const props = defineProps<{
...fieldProps, config: SwitchConfig;
config: { model: any;
type: Object as PropType<SwitchConfig>, initValues?: any;
required: true, values?: any;
}, name: string;
}, prop: string;
disabled?: boolean;
size: 'mini' | 'small' | 'medium';
}>();
emits: ['change'], const emit = defineEmits(['change']);
setup(props, { emit }) { useAddField(props.prop);
useAddField(props.prop);
return { const changeHandler = (value: number) => {
n: computed(() => props.name || props.config.name || ''), emit('change', value);
activeValue: computed(() => { };
if (typeof props.config.activeValue === 'undefined') {
if (props.config.filter === 'number') {
return 1;
}
} else {
return props.config.activeValue;
}
return true; const activeValue = computed(() => {
}), if (typeof props.config.activeValue === 'undefined') {
inactiveValue: computed(() => { if (props.config.filter === 'number') {
if (typeof props.config.inactiveValue === 'undefined') { return 1;
if (props.config.filter === 'number') { }
return 0; } else {
} return props.config.activeValue;
} else { }
return props.config.inactiveValue;
}
return false; return true;
}), });
changeHandler: (v: boolean | number | string) => {
emit('change', v); const inactiveValue = computed(() => {
}, if (typeof props.config.inactiveValue === 'undefined') {
}; if (props.config.filter === 'number') {
}, return 0;
}
} else {
return props.config.inactiveValue;
}
return false;
}); });
</script> </script>

View File

@ -1,6 +1,6 @@
<template> <template>
<el-input <TMagicInput
v-model="model[modelName]" v-model="model[name]"
clearable clearable
:size="size" :size="size"
:placeholder="config.placeholder" :placeholder="config.placeholder"
@ -20,117 +20,109 @@
{{ config.append.text }} {{ config.append.text }}
</el-button> </el-button>
</template> </template>
</el-input> </TMagicInput>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { computed, defineComponent, inject, PropType } from 'vue'; import { inject } from 'vue';
import { TMagicInput } from '@tmagic/design';
import { isNumber } from '@tmagic/utils'; import { isNumber } from '@tmagic/utils';
import { FormState, TextConfig } from '../schema'; import { FormState, TextConfig } from '../schema';
import fieldProps from '../utils/fieldProps';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';
export default defineComponent({ const props = defineProps<{
name: 'm-fields-text', config: TextConfig;
model: any;
initValues?: any;
values?: any;
name: string;
prop: string;
disabled?: boolean;
size: 'mini' | 'small' | 'medium';
}>();
props: { const emit = defineEmits(['change', 'input']);
...fieldProps,
config: {
type: Object as PropType<TextConfig>,
required: true,
},
},
emits: ['change', 'input'], useAddField(props.prop);
setup(props, { emit }) { const mForm = inject<FormState | undefined>('mForm');
const mForm = inject<FormState | undefined>('mForm');
useAddField(props.prop); const changeHandler = (value: number) => {
emit('change', value);
};
const modelName = computed(() => props.name || props.config.name || ''); const inputHandler = (v: string) => {
return { emit('input', v);
modelName, mForm?.$emit('field-input', props.prop, v);
};
changeHandler(v: string | number) { const buttonClickHandler = () => {
emit('change', v); if (typeof props.config.append === 'string') return;
},
inputHandler(v: string | number) { if (props.config.append?.handler) {
emit('input', v); props.config.append.handler(mForm, {
mForm?.$emit('field-input', props.prop, v); model: props.model,
}, values: mForm?.values,
});
}
};
buttonClickHandler() { const keyUpHandler = ($event: KeyboardEvent) => {
if (typeof props.config.append === 'string') return; if (!props.model) return;
if (!props.name) return;
if (props.config.append?.handler) { const arrowUp = $event.key === 'ArrowUp';
props.config.append.handler(mForm, { const arrowDown = $event.key === 'ArrowDown';
model: props.model,
values: mForm?.values,
});
}
},
keyUpHandler($event: KeyboardEvent) { if (!arrowUp && !arrowDown) {
if (!props.model) return; return;
if (!modelName.value) return; }
const arrowUp = $event.key === 'ArrowUp'; const value = props.model[props.name];
const arrowDown = $event.key === 'ArrowDown'; let num;
let unit;
if (isNumber(value)) {
num = +value;
} else {
value.replace(/^([0-9.]+)([a-z%]+)$/, ($0: string, $1: string, $2: string) => {
num = +$1;
unit = $2;
});
}
if (!arrowUp && !arrowDown) { if (num === undefined) {
return; return;
} }
const value = props.model[modelName.value]; const ctrl = navigator.platform.match('Mac') ? $event.metaKey : $event.ctrlKey;
let num; const shift = $event.shiftKey;
let unit; const alt = $event.altKey;
if (isNumber(value)) {
num = +value;
} else {
value.replace(/^([0-9.]+)([a-z%]+)$/, ($0: string, $1: string, $2: string) => {
num = +$1;
unit = $2;
});
}
if (num === undefined) { if (arrowUp) {
return; if (ctrl) {
} num += 100;
} else if (alt) {
num = (num * 10000 + 1000) / 10000;
} else if (shift) {
num = num + 10;
} else {
num += 1;
}
} else if (arrowDown) {
if (ctrl) {
num -= 100;
} else if (alt) {
num = (num * 10000 - 1000) / 10000;
} else if (shift) {
num -= 10;
} else {
num -= 1;
}
}
const ctrl = navigator.platform.match('Mac') ? $event.metaKey : $event.ctrlKey; props.model[props.name] = `${num}${unit || ''}`;
const shift = $event.shiftKey; emit('change', props.model[props.name]);
const alt = $event.altKey; };
if (arrowUp) {
if (ctrl) {
num += 100;
} else if (alt) {
num = (num * 10000 + 1000) / 10000;
} else if (shift) {
num = num + 10;
} else {
num += 1;
}
} else if (arrowDown) {
if (ctrl) {
num -= 100;
} else if (alt) {
num = (num * 10000 - 1000) / 10000;
} else if (shift) {
num -= 10;
} else {
num -= 1;
}
}
props.model[modelName.value] = `${num}${unit || ''}`;
emit('change', props.model[modelName.value]);
},
};
},
});
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-input <TMagicInput
v-model="model[name]" v-model="model[name]"
type="textarea" type="textarea"
:size="size" :size="size"
@ -9,52 +9,40 @@
@change="changeHandler" @change="changeHandler"
@input="inputHandler" @input="inputHandler"
> >
</el-input> </TMagicInput>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent, inject, PropType } from 'vue'; import { inject } from 'vue';
import { TMagicInput } from '@tmagic/design';
import { FormState, TextareaConfig } from '../schema'; import { FormState, TextareaConfig } from '../schema';
import fieldProps from '../utils/fieldProps';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';
export default defineComponent({
name: 'm-fields-textarea',
props: { const props = defineProps<{
...fieldProps, config: TextareaConfig;
config: { model: any;
type: Object as PropType<TextareaConfig>, initValues?: any;
required: true, values?: any;
}, name: string;
}, prop: string;
disabled?: boolean;
size: 'mini' | 'small' | 'medium';
}>();
emits: { const emit = defineEmits(['change', 'input']);
change(values: string | number) {
return values;
},
input(values: string | number) { useAddField(props.prop);
return values;
},
},
setup(props, { emit }) { const mForm = inject<FormState | null>('mForm');
useAddField(props.prop);
const mForm = inject<FormState | null>('mForm'); const changeHandler = (value: number) => {
emit('change', value);
};
return { const inputHandler = (v: string) => {
mForm, emit('input', v);
changeHandler: (v: string) => { mForm?.$emit('field-input', props.prop, v);
emit('change', v); };
},
inputHandler: (v: string) => {
emit('input', v);
mForm?.$emit('field-input', props.prop, v);
},
};
},
});
</script> </script>

View File

@ -1,46 +1,35 @@
<template> <template>
<el-time-picker <TMagicTimePicker
v-model="model[name]" v-model="model[name]"
:size="size" :size="size"
value-format="HH:mm:ss"
:placeholder="config.placeholder" :placeholder="config.placeholder"
:disabled="disabled" :disabled="disabled"
@change="changeHandler" @change="changeHandler"
></el-time-picker> ></TMagicTimePicker>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent, PropType } from 'vue'; import { TMagicTimePicker } from '@tmagic/design';
import { TimeConfig } from '../schema'; import { TimeConfig } from '../schema';
import fieldProps from '../utils/fieldProps';
import { useAddField } from '../utils/useAddField'; import { useAddField } from '../utils/useAddField';
export default defineComponent({ const props = defineProps<{
name: 'm-fields-time', config: TimeConfig;
model: any;
initValues?: any;
values?: any;
name: string;
prop: string;
disabled?: boolean;
size: 'mini' | 'small' | 'medium';
}>();
props: { const emit = defineEmits(['change']);
...fieldProps,
config: {
type: Object as PropType<TimeConfig>,
required: true,
},
},
emits: { useAddField(props.prop);
change(values: Date) {
return values;
},
},
setup(props, { emit }) { const changeHandler = (v: string) => {
useAddField(props.prop); emit('change', v);
};
return {
changeHandler: (v: Date) => {
emit('change', v);
},
};
},
});
</script> </script>

View File

@ -18,6 +18,8 @@
import { App } from 'vue'; import { App } from 'vue';
import TMagicDesign from '@tmagic/design';
import Container from './containers/Container.vue'; import Container from './containers/Container.vue';
import Fieldset from './containers/Fieldset.vue'; import Fieldset from './containers/Fieldset.vue';
import GroupList from './containers/GroupList.vue'; import GroupList from './containers/GroupList.vue';
@ -53,7 +55,6 @@ import './theme/index.scss';
export * from './schema'; export * from './schema';
export * from './utils/form'; export * from './utils/form';
export * from './utils/useAddField'; export * from './utils/useAddField';
export { default as fieldProps } from './utils/fieldProps';
export { default as MForm } from './Form.vue'; export { default as MForm } from './Form.vue';
export { default as MFormDialog } from './FormDialog.vue'; export { default as MFormDialog } from './FormDialog.vue';
@ -86,40 +87,42 @@ export { default as MDynamicField } from './fields/DynamicField.vue';
const defaultInstallOpt = {}; const defaultInstallOpt = {};
const install = (app: App, opt: any) => { const install = (app: App, opt: any) => {
app.use(TMagicDesign, opt.uiAdapter);
const option = Object.assign(defaultInstallOpt, opt); const option = Object.assign(defaultInstallOpt, opt);
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
app.config.globalProperties.$MAGIC_FORM = option; app.config.globalProperties.$MAGIC_FORM = option;
setConfig(option); setConfig(option);
app.component(Form.name, Form); app.component('m-form', Form);
app.component(FormDialog.name, FormDialog); app.component('m-form-dialog', FormDialog);
app.component(Container.name, Container); app.component('m-form-container', Container);
app.component('m-form-fieldset', Fieldset); app.component('m-form-fieldset', Fieldset);
app.component(GroupList.name, GroupList); app.component('m-form-group-list', GroupList);
app.component(Panel.name, Panel); app.component('m-form-panel', Panel);
app.component(Row.name, Row); app.component('m-form-row', Row);
app.component(MStep.name, MStep); app.component('m-form-step', MStep);
app.component('m-form-table', Table); app.component('m-form-table', Table);
app.component(Tabs.name, Tabs); app.component('m-form-tab', Tabs);
app.component(Text.name, Text); app.component('m-fields-text', Text);
app.component(Number.name, Number); app.component('m-fields-number', Number);
app.component(Textarea.name, Textarea); app.component('m-fields-textarea', Textarea);
app.component('m-fields-hidden', Hidden); app.component('m-fields-hidden', Hidden);
app.component(Date.name, Date); app.component('m-fields-date', Date);
app.component(DateTime.name, DateTime); app.component('m-fields-datetime', DateTime);
app.component(Time.name, Time);
app.component(Checkbox.name, Checkbox);
app.component(Switch.name, Switch);
app.component('m-fields-daterange', Daterange); app.component('m-fields-daterange', Daterange);
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-color-picker', ColorPicker);
app.component(CheckboxGroup.name, CheckboxGroup); app.component('m-fields-checkbox-group', CheckboxGroup);
app.component(RadioGroup.name, RadioGroup); app.component('m-fields-radio-group', RadioGroup);
app.component('m-fields-display', Display); app.component('m-fields-display', Display);
app.component(Link.name, Link); app.component('m-fields-link', Link);
app.component(Select.name, Select); app.component('m-fields-select', Select);
app.component(Cascader.name, Cascader); app.component('m-fields-cascader', Cascader);
app.component(DynamicField.name, DynamicField); app.component('m-fields-dynamic-field', DynamicField);
}; };
export default { export default {

View File

@ -16,6 +16,11 @@
* limitations under the License. * limitations under the License.
*/ */
export interface ValidateError {
message: string;
field: string;
}
/** /**
* *
*/ */
@ -167,7 +172,7 @@ type DefaultValueFunction = (mForm: FormState | undefined) => any;
/** /**
* *
*/ */
export interface SelectOption { export interface SelectConfigOption {
/** 选项的标签 */ /** 选项的标签 */
text: string | SelectOptionTextFunction; text: string | SelectOptionTextFunction;
/** 选项的值 */ /** 选项的值 */
@ -176,10 +181,19 @@ export interface SelectOption {
disabled?: boolean; disabled?: boolean;
} }
export interface SelectOption {
/** 选项的标签 */
text: string;
/** 选项的值 */
value: any;
/** 是否禁用该选项 */
disabled?: boolean;
}
/** /**
* *
*/ */
export interface SelectGroupOption { export interface SelectConfigGroupOption {
/** 分组的组名 */ /** 分组的组名 */
label: string; label: string;
/** 是否禁用该选项组 */ /** 是否禁用该选项组 */
@ -194,6 +208,21 @@ export interface SelectGroupOption {
}[]; }[];
} }
export interface SelectGroupOption {
/** 分组的组名 */
label: string;
/** 是否禁用该选项组 */
disabled: boolean;
options: {
/** 选项的标签 */
label: string;
/** 选项的值 */
value: any;
/** 是否禁用该选项 */
disabled?: boolean;
}[];
}
type SelectOptionFunction = ( type SelectOptionFunction = (
mForm: FormState | undefined, mForm: FormState | undefined,
data: { data: {
@ -226,11 +255,11 @@ type RemoteSelectOptionRequestFunction = (
}, },
) => any; ) => any;
type RemoteSelectOptionItemFunction = (optionsData: Record<string, any>) => SelectOption[]; type RemoteSelectOptionItemFunction = (optionsData: Record<string, any>) => SelectOption[] | SelectGroupOption[];
type SelectOptionValueFunction = (item: Record<string, any>) => any; type SelectOptionValueFunction = (item: Record<string, any>) => any;
type SelectOptionTextFunction = (item: Record<string, any>) => string; type SelectOptionTextFunction = (item: Record<string, any>) => string;
interface CascaderOption { export interface CascaderOption {
/** 指定选项的值为选项对象的某个属性值 */ /** 指定选项的值为选项对象的某个属性值 */
value: any; value: any;
/** 指定选项标签为选项对象的某个属性值 */ /** 指定选项标签为选项对象的某个属性值 */
@ -302,7 +331,7 @@ export interface NumberConfig extends FormItem {
min?: number; min?: number;
max?: number; max?: number;
step?: number; step?: number;
placeholder?: number; placeholder?: string;
} }
/** /**
@ -361,7 +390,7 @@ export interface SwitchConfig extends FormItem {
export interface RadioGroupConfig extends FormItem { export interface RadioGroupConfig extends FormItem {
type: 'radio-group'; type: 'radio-group';
options: { options: {
values: string | number | boolean; value: string | number | boolean;
text: string; text: string;
}[]; }[];
} }
@ -381,6 +410,7 @@ export interface CheckboxGroupConfig extends FormItem {
options: { options: {
value: any; value: any;
text: string; text: string;
disabled?: boolean;
}[]; }[];
} }
@ -394,7 +424,7 @@ export interface SelectConfig extends FormItem, Input {
valueKey?: string; valueKey?: string;
allowCreate?: boolean; allowCreate?: boolean;
group?: boolean; group?: boolean;
options: SelectOption[] | SelectGroupOption[] | SelectOptionFunction; options: SelectConfigOption[] | SelectConfigGroupOption[] | SelectOptionFunction;
remote: true; remote: true;
option: { option: {
url: string; url: string;
@ -520,7 +550,7 @@ export interface TabPaneConfig {
} }
export interface TabConfig extends FormItem, ContainerCommonConfig { export interface TabConfig extends FormItem, ContainerCommonConfig {
type: 'tab' | 'dynamic-tab'; type: 'tab' | 'dynamic-tab';
tabType?: 'tab'; tabType?: string;
editable?: boolean; editable?: boolean;
dynamic?: boolean; dynamic?: boolean;
tabPosition?: 'top' | 'right' | 'bottom' | 'left'; tabPosition?: 'top' | 'right' | 'bottom' | 'left';

View File

@ -1,39 +0,0 @@
/*
* Tencent is pleased to support the open source community by making TMagicEditor available.
*
* Copyright (C) 2021 THL A29 Limited, a Tencent company. 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 { PropType } from 'vue';
export default {
model: {
type: Object,
required: true,
default: () => ({}),
},
name: {
type: String,
default: '',
},
disabled: {
type: Boolean,
default: false,
},
size: String as PropType<'mini' | 'small' | 'medium'>,
prop: String,
initValues: Object,
values: Object,
};

View File

@ -30,7 +30,10 @@ export default defineConfig({
alias: alias:
process.env.NODE_ENV === 'production' process.env.NODE_ENV === 'production'
? [] ? []
: [{ find: /^@tmagic\/utils/, replacement: path.join(__dirname, '../utils/src/index.ts') }], : [
{ find: /^@tmagic\/utils/, replacement: path.join(__dirname, '../utils/src/index.ts') },
{ find: /^@tmagic\/design/, replacement: path.join(__dirname, '../design/src/index.ts') },
],
}, },
build: { build: {