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,96 +19,55 @@
: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;
}>(),
{
config: () => [],
initValues: () => ({}),
parentValues: () => ({}),
labelWidth: '200px',
disabled: false,
height: 'auto',
stepActive: 1,
inline: false,
labelPosition: 'right',
keyProp: '__key',
}, },
);
parentValues: { const emit = defineEmits(['change', 'field-input', 'field-change']);
type: Object,
default: () => ({}),
},
// const tMagicForm = ref<InstanceType<typeof TMagicForm>>();
config: {
type: Array as PropType<FormConfig>,
required: true,
default: () => [],
},
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'],
setup(props, { emit }) {
// InstanceType<typeof ElForm>types
const elForm = ref<any>();
const initialized = ref(false); const initialized = ref(false);
const values = ref<FormValue>({}); const values = ref<FormValue>({});
const fields = new Map<string, any>(); const fields = new Map<string, any>();
@ -157,22 +116,22 @@ export default defineComponent({
{ immediate: true }, { immediate: true },
); );
return { const changeHandler = () => {
initialized,
values,
elForm,
formState,
changeHandler: () => {
emit('change', values.value); emit('change', values.value);
}, };
resetForm: () => elForm.value?.resetFields(), defineExpose({
values,
formState,
initialized,
changeHandler,
resetForm: () => tMagicForm.value?.resetFields(),
submitForm: async (native?: boolean): Promise<any> => { submitForm: async (native?: boolean): Promise<any> => {
try { try {
await elForm.value?.validate(); await tMagicForm.value?.validate();
return native ? values.value : cloneDeep(toRaw(values.value)); return native ? values.value : cloneDeep(toRaw(values.value));
} catch (invalidFields: any) { } catch (invalidFields: any) {
const error: string[] = []; const error: string[] = [];
@ -187,7 +146,5 @@ export default defineComponent({
throw new Error(error.join('<br>')); 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,78 +24,65 @@
: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;
size?: 'small' | 'default' | 'large';
confirmText?: string;
}>(),
{
config: () => [],
values: () => ({}),
confirmText: '确定',
}, },
);
parentValues: { const emit = defineEmits(['close', 'submit', 'error', 'change']);
type: Object,
},
width: [Number, String],
fullscreen: Boolean,
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'],
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);
@ -153,21 +140,12 @@ export default defineComponent({
emit('change', value); emit('change', value);
}; };
return { defineExpose({
form, form,
saveFetch, saveFetch,
stepActive,
dialogVisible, dialogVisible,
bodyHeight,
stepCount,
hasStep,
cancel, cancel,
closeHandler,
save, 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,
size: String,
},
emits: ['change'],
setup(props, { emit }) {
const mForm = inject<FormState | undefined>('mForm'); const mForm = inject<FormState | undefined>('mForm');
const display = computed(() => displayFunction(mForm, props.config.display, props));
const changeHandler = () => emit('change', props.model); 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,60 +92,44 @@
: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: { const emit = defineEmits(['change']);
type: Object as PropType<ChildConfig>,
required: true,
},
prop: {
type: String,
default: () => '',
},
stepActive: {
type: [String, Number],
},
size: {
type: String,
default: 'small',
},
},
emits: ['change'],
setup(props, { emit }) {
const mForm = inject<FormState | undefined>('mForm'); const mForm = inject<FormState | undefined>('mForm');
const expand = ref(false); const expand = ref(false);
@ -270,24 +254,4 @@ export default defineComponent({
} }
emit('change', props.model); emit('change', props.model);
}; };
return {
expand,
name,
type,
disabled,
itemProp,
items,
display,
itemLabelWidth,
tagName,
rule,
tooltip,
extra,
key,
onChangeHandler,
expandHandler,
};
},
});
</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,57 +19,36 @@
@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: {
labelWidth: String,
model: {
type: Object,
default: () => ({}),
},
config: {
type: Object as PropType<GroupListConfig>,
default: () => ({}),
},
prop: {
type: String,
default: '',
},
size: String,
name: {
type: String,
default: '',
},
},
emits: ['change'],
setup(props, { emit }) {
const mForm = inject<FormState | undefined>('mForm'); const mForm = inject<FormState | undefined>('mForm');
const addable = computed(() => { const addable = computed(() => {
@ -142,15 +121,4 @@ export default defineComponent({
text: null, text: null,
}))) as any; }))) as any;
}; };
return {
Grid,
addable,
toggleMode,
removeHandler,
swapHandler,
changeHandler,
addHandler,
};
},
});
</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,53 +35,33 @@
: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: {
type: Object,
default: () => ({}),
},
config: {
type: Object as PropType<GroupListConfig>,
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 mForm = inject<FormState | undefined>('mForm');
const expand = ref(false); const expand = ref(false);
@ -139,21 +119,4 @@ export default defineComponent({
} }
return movable; return movable;
}; };
return {
expand,
expandHandler,
title,
showDelete,
removeHandler,
movable,
changeOrder,
itemExtra,
rowConfig,
changeHandler,
length,
Delete,
};
},
});
</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,47 +43,34 @@
: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: {
type: Object,
default: () => ({}),
},
config: {
type: Object as PropType<PanelConfig>,
default: () => ({}),
},
prop: String,
size: String,
name: String,
},
emits: ['change'],
setup(props, { emit }) {
const mForm = inject<FormState | undefined>('mForm'); const mForm = inject<FormState | undefined>('mForm');
const expand = ref(props.config.expand !== false); const expand = ref(props.config.expand !== false);
@ -93,14 +80,4 @@ export default defineComponent({
const filter = (config: any) => filterFunction(mForm, config, props); const filter = (config: any) => filterFunction(mForm, config, props);
const changeHandler = () => emit('change', props.model); 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: {
labelWidth: String,
expandMore: Boolean,
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 mForm = inject<FormState | undefined>('mForm');
const changeHandler = () => emit('change', props.name ? props.model[props.name] : props.model); const changeHandler = () => emit('change', props.name ? props.model[props.name] : props.model);
return {
mForm,
changeHandler,
};
},
});
</script> </script>

View File

@ -1,65 +1,57 @@
<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;
size?: string;
}>(),
{
stepActive: 1,
}, },
);
config: { const emit = defineEmits(['change']);
type: Object as PropType<StepConfig>,
default: () => ({}),
},
stepActive: {
type: Number,
default: () => 1,
},
size: String,
labelWidth: String,
},
emits: ['change'],
setup(props, { emit }) {
const mForm = inject<FormState | undefined>('mForm'); const mForm = inject<FormState | undefined>('mForm');
const active = ref(1); const active = ref(1);
@ -75,8 +67,4 @@ export default defineComponent({
const changeHandler = () => { const changeHandler = () => {
emit('change', props.model); emit('change', props.model);
}; };
return { mForm, active, stepClick, changeHandler };
},
});
</script> </script>

View File

@ -2,10 +2,10 @@
<div ref="mTable" class="m-fields-table" :class="{ 'm-fields-table-item-extra': config.itemExtra }"> <div ref="mTable" class="m-fields-table" :class="{ 'm-fields-table-item-extra': config.itemExtra }">
<span v-if="config.extra" style="color: rgba(0, 0, 0, 0.45)" v-html="config.extra"></span> <span v-if="config.extra" style="color: rgba(0, 0, 0, 0.45)" v-html="config.extra"></span>
<div class="el-form-item__content"> <div class="el-form-item__content">
<el-tooltip content="拖拽可排序" placement="left-start" :disabled="config.dropSort !== true"> <TMagicTooltip content="拖拽可排序" placement="left-start" :disabled="config.dropSort !== true">
<el-table <TMagicTable
v-if="model[modelName]" v-if="model[modelName]"
ref="elTable" ref="tMagicTable"
style="width: 100%" style="width: 100%"
:data="model[modelName]" :data="model[modelName]"
:border="config.border" :border="config.border"
@ -15,31 +15,36 @@
@select="selectHandle" @select="selectHandle"
@sort-change="sortChange" @sort-change="sortChange"
> >
<el-table-column v-if="config.itemExtra" :fixed="'left'" width="30" type="expand"> <TMagicTableColumn v-if="config.itemExtra" :fixed="'left'" width="30" type="expand">
<template v-slot="scope"> <template v-slot="scope">
<span v-html="itemExtra(config.itemExtra, scope.$index)" class="m-form-tip"></span> <span v-html="itemExtra(config.itemExtra, scope.$index)" class="m-form-tip"></span>
</template> </template>
</el-table-column> </TMagicTableColumn>
<el-table-column label="操作" width="55" align="center" :fixed="config.fixed === false ? undefined : 'left'"> <TMagicTableColumn
label="操作"
width="55"
align="center"
:fixed="config.fixed === false ? undefined : 'left'"
>
<template v-slot="scope"> <template v-slot="scope">
<el-icon <TMagicIcon
v-show="showDelete(scope.$index + 1 + pagecontext * pagesize - 1)" v-show="showDelete(scope.$index + 1 + pagecontext * pagesize - 1)"
class="m-table-delete-icon" class="m-table-delete-icon"
@click="removeHandler(scope.$index + 1 + pagecontext * pagesize - 1)" @click="removeHandler(scope.$index + 1 + pagecontext * pagesize - 1)"
><Delete ><Delete
/></el-icon> /></TMagicIcon>
</template> </template>
</el-table-column> </TMagicTableColumn>
<el-table-column v-if="sort && model[modelName] && model[modelName].length > 1" label="排序" width="60"> <TMagicTableColumn v-if="sort && model[modelName] && model[modelName].length > 1" label="排序" width="60">
<template v-slot="scope"> <template v-slot="scope">
<el-tooltip <TMagicTooltip
v-if="scope.$index + 1 + pagecontext * pagesize - 1 !== 0"
content="点击上移,双击置顶" content="点击上移,双击置顶"
placement="top" placement="top"
v-if="scope.$index + 1 + pagecontext * pagesize - 1 !== 0"
> >
<el-button <TMagicButton
plain plain
size="small" size="small"
type="primary" type="primary"
@ -47,14 +52,14 @@
text text
@click="upHandler(scope.$index + 1 + pagecontext * pagesize - 1)" @click="upHandler(scope.$index + 1 + pagecontext * pagesize - 1)"
@dblclick="topHandler(scope.$index + 1 + pagecontext * pagesize - 1)" @dblclick="topHandler(scope.$index + 1 + pagecontext * pagesize - 1)"
></el-button> ></TMagicButton>
</el-tooltip> </TMagicTooltip>
<el-tooltip <TMagicTooltip
v-if="scope.$index + 1 + pagecontext * pagesize - 1 !== model[modelName].length - 1"
content="点击下移,双击置底" content="点击下移,双击置底"
placement="top" placement="top"
v-if="scope.$index + 1 + pagecontext * pagesize - 1 !== model[modelName].length - 1"
> >
<el-button <TMagicButton
plain plain
size="small" size="small"
type="primary" type="primary"
@ -62,25 +67,25 @@
text text
@click="downHandler(scope.$index + 1 + pagecontext * pagesize - 1)" @click="downHandler(scope.$index + 1 + pagecontext * pagesize - 1)"
@dblclick="bottomHandler(scope.$index + 1 + pagecontext * pagesize - 1)" @dblclick="bottomHandler(scope.$index + 1 + pagecontext * pagesize - 1)"
></el-button> ></TMagicButton>
</el-tooltip> </TMagicTooltip>
</template> </template>
</el-table-column> </TMagicTableColumn>
<el-table-column <TMagicTableColumn
v-if="selection" v-if="selection"
align="center" align="center"
header-align="center" header-align="center"
type="selection" type="selection"
width="45" width="45"
></el-table-column> ></TMagicTableColumn>
<el-table-column width="60" label="序号" v-if="showIndex && config.showIndex"> <TMagicTableColumn width="60" label="序号" v-if="showIndex && config.showIndex">
<template v-slot="scope">{{ scope.$index + 1 + pagecontext * pagesize }}</template> <template v-slot="scope">{{ scope.$index + 1 + pagecontext * pagesize }}</template>
</el-table-column> </TMagicTableColumn>
<template v-for="(column, index) in config.items"> <template v-for="(column, index) in config.items">
<el-table-column <TMagicTableColumn
v-if="column.type !== 'hidden' && display(column.display)" v-if="column.type !== 'hidden' && display(column.display)"
:prop="column.name" :prop="column.name"
:width="column.width" :width="column.width"
@ -91,7 +96,7 @@
:class-name="config.dropSort === true ? 'el-table__column--dropable' : ''" :class-name="config.dropSort === true ? 'el-table__column--dropable' : ''"
> >
<template #default="scope"> <template #default="scope">
<m-form-container <Container
v-if="scope.$index > -1" v-if="scope.$index > -1"
labelWidth="0" labelWidth="0"
:prop="getProp(scope.$index)" :prop="getProp(scope.$index)"
@ -100,18 +105,23 @@
:model="scope.row" :model="scope.row"
:size="size" :size="size"
@change="$emit('change', model[modelName])" @change="$emit('change', model[modelName])"
></m-form-container> ></Container>
</template> </template>
</el-table-column> </TMagicTableColumn>
</template> </template>
</el-table> </TMagicTable>
</el-tooltip> </TMagicTooltip>
<slot></slot> <slot></slot>
<el-button v-if="addable" size="small" type="primary" plain @click="newHandler()">添加</el-button> &nbsp; <TMagicButton v-if="addable" size="small" type="primary" plain @click="newHandler()">添加</TMagicButton> &nbsp;
<el-button :icon="Grid" size="small" type="primary" @click="toggleMode" v-if="enableToggleMode && !isFullscreen" <TMagicButton
>展开配置</el-button :icon="Grid"
size="small"
type="primary"
@click="toggleMode"
v-if="enableToggleMode && !isFullscreen"
>展开配置</TMagicButton
> >
<el-button <TMagicButton
:icon="FullScreen" :icon="FullScreen"
size="small" size="small"
type="primary" type="primary"
@ -119,8 +129,8 @@
v-if="config.enableFullscreen !== false" v-if="config.enableFullscreen !== false"
> >
{{ isFullscreen ? '退出全屏' : '全屏编辑' }} {{ isFullscreen ? '退出全屏' : '全屏编辑' }}
</el-button> </TMagicButton>
<el-upload <TMagicUpload
v-if="importable" v-if="importable"
ref="excelBtn" ref="excelBtn"
action="/noop" action="/noop"
@ -128,13 +138,13 @@
:auto-upload="false" :auto-upload="false"
style="display: inline-block" style="display: inline-block"
> >
<el-button size="small" type="success" plain>导入EXCEL</el-button> </el-upload <TMagicButton size="small" type="success" plain>导入EXCEL</TMagicButton> </TMagicUpload
>&nbsp; >&nbsp;
<el-button v-if="importable" size="small" type="warning" plain @click="clearHandler()">清空</el-button> <TMagicButton v-if="importable" size="small" type="warning" plain @click="clearHandler()">清空</TMagicButton>
</div> </div>
<div class="bottom" style="text-align: right"> <div class="bottom" style="text-align: right">
<el-pagination <TMagicPagination
layout="total, sizes, prev, pager, next, jumper" layout="total, sizes, prev, pager, next, jumper"
:hide-on-single-page="model[modelName].length < pagesize" :hide-on-single-page="model[modelName].length < pagesize"
:current-page="pagecontext + 1" :current-page="pagecontext + 1"
@ -144,88 +154,63 @@
@size-change="handleSizeChange" @size-change="handleSizeChange"
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
> >
</el-pagination> </TMagicPagination>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
/* eslint-disable no-param-reassign */ import { computed, inject, onMounted, ref, toRefs } from 'vue';
import { computed, defineComponent, inject, onMounted, PropType, ref, toRefs } from 'vue';
import { ArrowDown, ArrowUp, Delete, FullScreen, Grid } from '@element-plus/icons-vue'; import { ArrowDown, ArrowUp, Delete, FullScreen, Grid } from '@element-plus/icons-vue';
import { ElMessage, UploadFile } from 'element-plus';
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
import Sortable, { SortableEvent } from 'sortablejs'; import Sortable, { SortableEvent } from 'sortablejs';
import {
TMagicButton,
TMagicIcon,
tMagicMessage,
TMagicPagination,
TMagicTable,
TMagicTableColumn,
TMagicTooltip,
TMagicUpload,
} from '@tmagic/design';
import { asyncLoadJs, sleep } from '@tmagic/utils'; import { asyncLoadJs, sleep } from '@tmagic/utils';
import { ColumnConfig, FormState, SortProp, TableConfig } from '../schema'; import { ColumnConfig, FormState, SortProp, TableConfig } from '../schema';
import { display, initValue } from '../utils/form'; import { display as displayFunc, initValue } from '../utils/form';
export default defineComponent({ import Container from './Container.vue';
props: {
name: { const props = withDefaults(
type: String, defineProps<{
required: true, model: any;
config: TableConfig;
name: string;
prop?: string;
labelWidth?: string;
sort?: boolean;
sortKey?: string;
text?: string;
size?: string;
enableToggleMode?: boolean;
showIndex?: boolean;
}>(),
{
prop: '',
sortKey: '',
enableToggleMode: true,
showIndex: true,
}, },
);
model: { const emit = defineEmits(['change', 'select']);
type: Object,
required: true,
default: () => ({}),
},
config: {
type: Object as PropType<TableConfig>,
required: true,
default: () => ({}),
},
prop: {
type: String,
},
labelWidth: {
type: String,
},
sort: {
type: Boolean,
default: false,
},
sortKey: {
type: String,
default: '',
},
text: {
type: String,
},
size: String,
enableToggleMode: {
type: Boolean,
default: true,
},
showIndex: {
type: Boolean,
default: true,
},
},
emits: ['change', 'select'],
components: { Delete },
setup(props, { emit }) {
let timer: any | null = null; let timer: any | null = null;
const mForm = inject<FormState | undefined>('mForm'); const mForm = inject<FormState | undefined>('mForm');
const elTable = ref<any>(); const tMagicTable = ref<InstanceType<typeof TMagicTable>>();
const excelBtn = ref<any>(); const excelBtn = ref<InstanceType<typeof TMagicUpload>>();
const mTable = ref<HTMLDivElement>(); const mTable = ref<HTMLDivElement>();
const pagesize = ref(10); const pagesize = ref(10);
@ -263,7 +248,7 @@ export default defineComponent({
}; };
const rowDrop = () => { const rowDrop = () => {
const tableEl = elTable.value?.$el; const tableEl = tMagicTable.value?.$el;
if (tableEl?.querySelectorAll('.el-table__body > tbody')) { if (tableEl?.querySelectorAll('.el-table__body > tbody')) {
// eslint-disable-next-line prefer-destructuring // eslint-disable-next-line prefer-destructuring
const el = tableEl.querySelectorAll('.el-table__body > tbody')[0]; const el = tableEl.querySelectorAll('.el-table__body > tbody')[0];
@ -292,7 +277,7 @@ export default defineComponent({
const newHandler = async (row?: any) => { const newHandler = async (row?: any) => {
if (props.config.max && props.model[modelName.value].length >= props.config.max) { if (props.config.max && props.model[modelName.value].length >= props.config.max) {
ElMessage.error(`最多新增配置不能超过${props.config.max}`); tMagicMessage.error(`最多新增配置不能超过${props.config.max}`);
return; return;
} }
@ -369,30 +354,7 @@ export default defineComponent({
} }
}); });
return { const addable = computed(() => {
mForm,
pagesize,
pagecontext,
foreUpdate,
isFullscreen,
elTable,
mTable,
excelBtn,
modelName,
updateKey,
ArrowDown,
ArrowUp,
Delete,
FullScreen,
Grid,
data: computed(() =>
props.model[modelName.value].filter(
(item: any, index: number) =>
index >= pagecontext.value * pagesize.value && index + 1 <= (pagecontext.value + 1) * pagesize.value,
),
),
addable: computed(() => {
if (!props.model[modelName.value].length) { if (!props.model[modelName.value].length) {
return true; return true;
} }
@ -404,14 +366,16 @@ export default defineComponent({
}); });
} }
return typeof props.config.addable === 'undefined' ? true : props.config.addable; return typeof props.config.addable === 'undefined' ? true : props.config.addable;
}), });
selection: computed(() => {
const selection = computed(() => {
if (typeof props.config.selection === 'function') { if (typeof props.config.selection === 'function') {
return props.config.selection(mForm, { model: props.model[modelName.value] }); return props.config.selection(mForm, { model: props.model[modelName.value] });
} }
return props.config.selection; return props.config.selection;
}), });
importable: computed(() => {
const importable = computed(() => {
if (typeof props.config.importable === 'function') { if (typeof props.config.importable === 'function') {
return props.config.importable(mForm, { return props.config.importable(mForm, {
formValue: mForm?.values, formValue: mForm?.values,
@ -419,15 +383,11 @@ export default defineComponent({
}); });
} }
return typeof props.config.importable === 'undefined' ? false : props.config.importable; return typeof props.config.importable === 'undefined' ? false : props.config.importable;
}), });
sortChange, const display = (fuc: any) => displayFunc(mForm, fuc, props);
display(fuc: any) { const itemExtra = (fuc: any, index: number) => {
return display(mForm, fuc, props);
},
itemExtra(fuc: any, index: number) {
if (typeof fuc === 'function') { if (typeof fuc === 'function') {
return fuc(mForm, { return fuc(mForm, {
values: mForm?.initValues, values: mForm?.initValues,
@ -439,37 +399,35 @@ export default defineComponent({
} }
return fuc; return fuc;
}, };
newHandler, const removeHandler = (index: number) => {
removeHandler(index: number) {
props.model[modelName.value].splice(index, 1); props.model[modelName.value].splice(index, 1);
emit('change', props.model[modelName.value]); emit('change', props.model[modelName.value]);
}, };
selectHandle(selection: any, row: any) { const selectHandle = (selection: any, row: any) => {
if (typeof props.config.selection === 'string' && props.config.selection === 'single') { if (typeof props.config.selection === 'string' && props.config.selection === 'single') {
elTable.value?.clearSelection(); tMagicTable.value?.clearSelection();
elTable.value?.toggleRowSelection(row, true); tMagicTable.value?.toggleRowSelection(row, true);
} }
emit('select', selection, row); emit('select', selection, row);
if (typeof props.config.onSelect === 'function') { if (typeof props.config.onSelect === 'function') {
props.config.onSelect(mForm, { selection, row, config: props.config }); props.config.onSelect(mForm, { selection, row, config: props.config });
} }
}, };
toggleRowSelection(row: any, selected: boolean) { const toggleRowSelection = (row: any, selected: boolean) => {
elTable.value?.toggleRowSelection.call(elTable.value, row, selected); tMagicTable.value?.toggleRowSelection.call(tMagicTable.value, row, selected);
}, };
makeConfig(config: ColumnConfig) { const makeConfig = (config: ColumnConfig) => {
const newConfig = cloneDeep(config); const newConfig = cloneDeep(config);
delete newConfig.display; delete newConfig.display;
return newConfig; return newConfig;
}, };
upHandler(index: number) { const upHandler = (index: number) => {
if (timer) { if (timer) {
clearTimeout(timer); clearTimeout(timer);
} }
@ -477,9 +435,9 @@ export default defineComponent({
timer = setTimeout(() => { timer = setTimeout(() => {
swapArray(index, index - 1); swapArray(index, index - 1);
}, 300); }, 300);
}, };
topHandler(index: number) { const topHandler = (index: number) => {
if (timer) { if (timer) {
clearTimeout(timer); clearTimeout(timer);
} }
@ -492,9 +450,9 @@ export default defineComponent({
swapArray(index, index - 1); swapArray(index, index - 1);
index -= 1; index -= 1;
} }
}, };
downHandler(index: number) { const downHandler = (index: number) => {
if (timer) { if (timer) {
clearTimeout(timer); clearTimeout(timer);
} }
@ -502,9 +460,9 @@ export default defineComponent({
timer = setTimeout(() => { timer = setTimeout(() => {
swapArray(index, index + 1); swapArray(index, index + 1);
}, 300); }, 300);
}, };
bottomHandler(index: number) { const bottomHandler = (index: number) => {
if (timer) { if (timer) {
clearTimeout(timer); clearTimeout(timer);
} }
@ -517,24 +475,24 @@ export default defineComponent({
swapArray(index, index + 1); swapArray(index, index + 1);
index += 1; index += 1;
} }
}, };
// //
showDelete(index: number) { const showDelete = (index: number) => {
const deleteFunc = props.config.delete; const deleteFunc = props.config.delete;
if (deleteFunc && typeof deleteFunc === 'function') { if (deleteFunc && typeof deleteFunc === 'function') {
return deleteFunc(props.model[modelName.value], index, mForm?.values); return deleteFunc(props.model[modelName.value], index, mForm?.values);
} }
return true; return true;
}, };
clearHandler() { const clearHandler = () => {
const len = props.model[modelName.value].length; const len = props.model[modelName.value].length;
props.model[modelName.value].splice(0, len); props.model[modelName.value].splice(0, len);
mForm?.$emit('field-change', props.prop, props.model[modelName.value]); mForm?.$emit('field-change', props.prop, props.model[modelName.value]);
}, };
excelHandler(file: UploadFile) { const excelHandler = (file: any) => {
if (!file || !file.raw) { if (!file || !file.raw) {
return false; return false;
} }
@ -557,17 +515,17 @@ export default defineComponent({
reader.readAsArrayBuffer(file.raw); reader.readAsArrayBuffer(file.raw);
return false; return false;
}, };
handleSizeChange(val: number) { const handleSizeChange = (val: number) => {
pagesize.value = val; pagesize.value = val;
}, };
handleCurrentChange(val: number) { const handleCurrentChange = (val: number) => {
pagecontext.value = val - 1; pagecontext.value = val - 1;
}, };
toggleMode() { const toggleMode = () => {
const calcLabelWidth = (label: string) => { const calcLabelWidth = (label: string) => {
if (!label) return '0px'; if (!label) return '0px';
const zhLength = label.match(/[^\x00-\xff]/g)?.length || 0; const zhLength = label.match(/[^\x00-\xff]/g)?.length || 0;
@ -591,9 +549,9 @@ export default defineComponent({
span: item.span || 12, span: item.span || 12,
}; };
}); });
}, };
toggleFullscreen() { const toggleFullscreen = () => {
if (isFullscreen.value) { if (isFullscreen.value) {
mTable.value?.classList.remove('fixed'); mTable.value?.classList.remove('fixed');
isFullscreen.value = false; isFullscreen.value = false;
@ -601,13 +559,14 @@ export default defineComponent({
mTable.value?.classList.add('fixed'); mTable.value?.classList.add('fixed');
isFullscreen.value = true; isFullscreen.value = true;
} }
}, };
getProp(index: number) { const getProp = (index: number) => {
const { prop } = toRefs(props); const { prop } = toRefs(props);
return `${prop.value}${prop.value ? '.' : ''}${index + 1 + pagecontext.value * pagesize.value - 1}`; return `${prop.value}${prop.value ? '.' : ''}${index + 1 + pagecontext.value * pagesize.value - 1}`;
},
}; };
},
defineExpose({
toggleRowSelection,
}); });
</script> </script>

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,37 +79,18 @@ 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: {
type: Object,
default: () => ({}),
},
config: {
type: Object as PropType<TabConfig>,
default: () => ({}),
},
prop: String,
name: String,
size: String,
},
emits: {
change(values: FormValue) {
return values;
},
},
setup(props, { emit }) {
const mForm = inject<FormState | undefined>('mForm'); const mForm = inject<FormState | undefined>('mForm');
const activeTabName = ref(getActive(mForm, props, '')); const activeTabName = ref(getActive(mForm, props, ''));
@ -128,20 +113,11 @@ const Tab = defineComponent({
} }
}); });
return { const tabItems = (tab: TabPaneConfig) => (props.config.dynamic ? props.config.items : tab.items);
mForm,
activeTabName, const tabClickHandler = (tab: any) => tabClick(mForm, tab, props);
tabs, const onTabAdd = () => {
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 (!props.config.name) throw new Error('dynamic tab 必须配置name');
if (typeof props.config.onTabAdd === 'function') { if (typeof props.config.onTabAdd === 'function') {
@ -157,9 +133,9 @@ const Tab = defineComponent({
} }
emit('change', props.model); emit('change', props.model);
mForm?.$emit('field-change', props.prop, props.model[props.config.name]); mForm?.$emit('field-change', props.prop, props.model[props.config.name]);
}, };
onTabRemove: (tabName: string) => { const onTabRemove = (tabName: string) => {
if (!props.config.name) throw new Error('dynamic tab 必须配置name'); if (!props.config.name) throw new Error('dynamic tab 必须配置name');
if (typeof props.config.onTabRemove === 'function') { if (typeof props.config.onTabRemove === 'function') {
@ -174,24 +150,19 @@ const Tab = defineComponent({
// //
if (tabName < activeTabName.value || activeTabName.value >= props.model[props.config.name].length) { if (tabName < activeTabName.value || activeTabName.value >= props.model[props.config.name].length) {
activeTabName.value = (+activeTabName.value - 1).toString(); activeTabName.value = (+activeTabName.value - 1).toString();
tabClickHandler(mForm, { name: activeTabName.value }, props); tabClick(mForm, { name: activeTabName.value }, props);
} }
} }
emit('change', props.model); emit('change', props.model);
mForm?.$emit('field-change', props.prop, props.model[props.config.name]); mForm?.$emit('field-change', props.prop, props.model[props.config.name]);
}, };
display: (displayConfig: any) => display(mForm, displayConfig, props), const display = (displayConfig: any) => displayFunc(mForm, displayConfig, props);
changeHandler: () => { const changeHandler = () => {
emit('change', props.model); emit('change', props.model);
if (typeof props.config.onChange === 'function') { if (typeof props.config.onChange === 'function') {
props.config.onChange(mForm, { model: props.model, prop: props.prop, config: props.config }); props.config.onChange(mForm, { model: props.model, prop: props.prop, config: props.config });
} }
},
}; };
},
});
export default Tab;
</script> </script>

View File

@ -1,8 +1,7 @@
<template> <template>
<div class="m-cascader" style="width: 100%"> <TMagicCascader
<el-cascader
v-model="model[name]" v-model="model[name]"
ref="cascader" ref="tMagicCascader"
style="width: 100%" style="width: 100%"
clearable clearable
filterable filterable
@ -12,50 +11,38 @@
:options="options" :options="options"
:props="{ multiple: config.multiple }" :props="{ multiple: config.multiple }"
@change="changeHandler" @change="changeHandler"
></el-cascader> ></TMagicCascader>
</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'],
setup(props, { emit }) {
const mForm = inject<FormState | null>('mForm'); const mForm = inject<FormState | null>('mForm');
const vm = getCurrentInstance() as ComponentInternalInstance;
useAddField(props.prop); useAddField(props.prop);
const requestFunc = getConfig('request') as Function; const requestFunc = getConfig('request') as Function;
const cascader = ref<any>(); const tMagicCascader = ref<InstanceType<typeof TMagicCascader>>();
const dialog = ref<any>();
const options = Array.isArray(props.config.options) ? ref(props.config.options) : ref([]); const options = Array.isArray(props.config.options) ? ref(props.config.options) : ref([]);
const remoteData = ref<any>(null); const remoteData = ref<any>(null);
@ -96,51 +83,16 @@ export default defineComponent({
// //
if (typeof props.config.options === 'function' && props.model && mForm) { if (typeof props.config.options === 'function' && props.model && mForm) {
watchEffect( watchEffect(
() => () => (options.value = (props.config.options as Function)(mForm, { model: props.model, formValues: mForm.values })),
(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) { } else if (!props.config.options || !props.config.options.length || props.config.remote) {
Promise.resolve(setRemoteOptions()); Promise.resolve(setRemoteOptions());
} }
const action = computed(() => { const changeHandler = (value: any) => {
if (props.config.add?.action.method === 'post') { if (!tMagicCascader.value) return;
return (options: any) => tMagicCascader.value.setQuery('');
requestFunc({ tMagicCascader.value.setPreviousQuery(null);
...props.config?.add?.action.body,
...options,
});
}
return null;
});
return {
options,
remoteData,
addButtonStyle: {
top: 0,
left: 0,
width: 'auto',
},
dialogVisible: false,
cascader,
dialog,
action,
setRemoteOptions,
changeHandler: (value: any) => {
if (!cascader.value) return;
cascader.value.query = '';
cascader.value.previousQuery = null;
emit('change', value); emit('change', value);
},
addHandler: () => {
if (!dialog.value) return;
dialog.value.dialogVisible = true;
},
editAfterAction: () => {
setRemoteOptions();
},
}; };
},
});
</script> </script>

View File

@ -1,40 +1,39 @@
<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'],
setup(props, { emit }) {
useAddField(props.prop); useAddField(props.prop);
return { const activeValue = computed(() => {
activeValue: computed(() => {
if (typeof props.config.activeValue === 'undefined') { if (typeof props.config.activeValue === 'undefined') {
if (props.config.filter === 'number') { if (props.config.filter === 'number') {
return 1; return 1;
@ -44,9 +43,9 @@ export default defineComponent({
} }
return undefined; return undefined;
}), });
inactiveValue: computed(() => { const inactiveValue = computed(() => {
if (typeof props.config.inactiveValue === 'undefined') { if (typeof props.config.inactiveValue === 'undefined') {
if (props.config.filter === 'number') { if (props.config.filter === 'number') {
return 0; return 0;
@ -56,12 +55,9 @@ export default defineComponent({
} }
return undefined; return undefined;
}),
changeHandler(value: number | boolean) {
emit('change', value);
},
};
},
}); });
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'],
setup(props, { emit }) {
useAddField(props.prop); useAddField(props.prop);
// //
if (props.model && !props.model[props.name]) { if (props.model && !props.model[props.name]) {
// eslint-disable-next-line no-param-reassign
props.model[props.name] = []; props.model[props.name] = [];
} }
return {
changeHandler: (v: Array<string | number | boolean>) => { const changeHandler = (v: Array<string | number | boolean>) => {
emit('change', v); 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'],
setup(props, { emit }) {
useAddField(props.prop); useAddField(props.prop);
props.model[props.name] = datetimeFormatter(props.model[props.name], ''); props.model[props.name] = datetimeFormatter(props.model[props.name], '');
return {
changeHandler(v: string) { const changeHandler = (v: string) => {
emit('change', v); 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,32 +10,29 @@
: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'],
setup(props, { emit }) {
useAddField(props.prop); useAddField(props.prop);
const value = props.model?.[props.name].toString(); const value = props.model?.[props.name].toString();
@ -47,12 +44,7 @@ export default defineComponent({
} }
} }
return { const changeHandler = (v: string) => {
value,
changeHandler: (v: Date) => {
emit('change', v); 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,27 +23,27 @@
* 特别注意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'],
setup(props, { emit }) {
useAddField(props.prop); useAddField(props.prop);
const request = getConfig('request') as Function; const request = getConfig('request') as Function;
@ -89,21 +89,7 @@ export default defineComponent({
} }
}); });
return { const inputChangeHandler = (key: string) => {
request,
fieldMap,
fieldLabelMap,
unwatch,
changeFieldMap,
inputChangeHandler: (key: string) => {
emit('change', fieldMap.value[key], key); emit('change', fieldMap.value[key], key);
},
}; };
},
methods: {
init() {},
},
});
</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,32 +12,32 @@
: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'],
setup(props, { emit }) {
useAddField(props.prop); useAddField(props.prop);
const formValue = ref({}); const formValue = ref({});
@ -55,15 +55,7 @@ export default defineComponent({
formValue.value = props.model?.[props.name] || {}; formValue.value = props.model?.[props.name] || {};
}; };
return { const formConfig = computed(() => {
// ref
formValue,
editor,
// computed methods
href,
formConfig: computed(() => {
if (typeof props.config.form === 'function') { if (typeof props.config.form === 'function') {
return props.config.form(mForm, { return props.config.form(mForm, {
model: props.model || {}, model: props.model || {},
@ -71,16 +63,9 @@ export default defineComponent({
}); });
} }
return props.config.form; return props.config.form;
}), });
disable: computed(() => { const displayText = computed(() => {
if (typeof props.config.disabled !== 'undefined') {
return props.config.disabled;
}
return !href.value;
}),
displayText: computed(() => {
if (typeof props.config.displayText === 'function') { if (typeof props.config.displayText === 'function') {
return props.config.displayText(mForm, { model: props.model || {} }); return props.config.displayText(mForm, { model: props.model || {} });
} }
@ -88,25 +73,19 @@ export default defineComponent({
return props.config.displayText; return props.config.displayText;
} }
return '跳转'; return '跳转';
}), });
// methods const editHandler = () => {
init,
editHandler: () => {
init(); init();
editor.value && (editor.value.dialogVisible = true); editor.value && (editor.value.dialogVisible = true);
}, };
action: (data: any) => { const action = (data: any) => {
if (props.model) { if (props.model) {
props.model[props.name] = data; props.model[props.name] = data;
formValue.value = data; formValue.value = data;
emit('change', props.model[props.name]); emit('change', props.model[props.name]);
} }
editor.value && (editor.value.dialogVisible = false); 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);
return {
changeHandler: (v: string | number | boolean) => emit('change', v),
}; };
},
}); useAddField(props.prop);
</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,43 +19,41 @@
@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: {
...fieldProps,
config: {
type: Object as PropType<SelectConfig>,
required: true,
},
},
emits: ['change'],
setup(props, { emit }) {
if (!props.model) throw new Error('不能没有model'); if (!props.model) throw new Error('不能没有model');
useAddField(props.prop); useAddField(props.prop);
const select = ref<any>(); const tMagicSelect = ref<InstanceType<typeof TMagicSelect>>();
const mForm = inject<FormState | undefined>('mForm'); const mForm = inject<FormState | undefined>('mForm');
const options = ref<SelectOption[] | SelectGroupOption[]>([]); const options = ref<SelectOption[] | SelectGroupOption[]>([]);
const localOptions = ref<SelectOption[] | SelectGroupOption[]>([]); const localOptions = ref<SelectOption[] | SelectGroupOption[]>([]);
@ -206,9 +204,7 @@ export default defineComponent({
} }
if (config.multiple && value.findIndex) { if (config.multiple && value.findIndex) {
return (localOptions.value as any[]).filter( return (localOptions.value as any[]).filter((item) => value.findIndex((v: any) => equalValue(item.value, v)) > -1);
(item) => value.findIndex((v: any) => equalValue(item.value, v)) > -1,
);
} }
return (localOptions.value as any[]).filter((item) => equalValue(item.value, value)); return (localOptions.value as any[]).filter((item) => equalValue(item.value, value));
}; };
@ -295,8 +291,9 @@ export default defineComponent({
} }
props.config.remote && props.config.remote &&
onMounted(() => { onMounted(async () => {
select.value?.scrollbar.wrap$.addEventListener('scroll', async (e: Event) => { await nextTick();
tMagicSelect.value?.scrollbarWrap?.addEventListener('scroll', async (e: Event) => {
const el = e.currentTarget as HTMLDivElement; const el = e.currentTarget as HTMLDivElement;
if (moreLoadingVisible.value) { if (moreLoadingVisible.value) {
return; return;
@ -314,39 +311,26 @@ export default defineComponent({
}); });
}); });
return { const popperClass = mForm?.popperClass;
select,
loading,
remote,
options: options as Ref<SelectOption[]>,
groupOptions: options as Ref<SelectGroupOption[]>,
moreLoadingVisible,
popperClass: mForm?.popperClass,
getOptions, const changeHandler = (value: any) => {
getRequestFuc() {
return getConfig('request');
},
changeHandler(value: any) {
emit('change', value); emit('change', value);
}, };
async visibleHandler(visible: boolean) { const visibleHandler = async (visible: boolean) => {
if (!visible) return; if (!visible) return;
if (!props.config.remote) return; if (!props.config.remote) return;
if (query.value && select.value) { if (query.value && tMagicSelect.value) {
select.value.query = query.value; tMagicSelect.value.setQuery(query.value);
select.value.previousQuery = query.value; tMagicSelect.value.setPreviousQuery(query.value);
select.value.selectedLabel = query.value; tMagicSelect.value.setSelectedLabel(query.value);
} else if (options.value.length <= (props.config.multiple ? props.model?.[props.name].length : 1)) { } else if (options.value.length <= (props.config.multiple ? props.model?.[props.name].length : 1)) {
options.value = await getOptions(); options.value = await getOptions();
} }
}, };
async remoteMethod(q: string) { const remoteMethod = async (q: string) => {
if (!localOptions.value.length) { if (!localOptions.value.length) {
query.value = q; query.value = q;
pgIndex.value = 0; pgIndex.value = 0;
@ -354,11 +338,11 @@ export default defineComponent({
// el-select // el-select
if (props.config.multiple) if (props.config.multiple)
setTimeout(() => { setTimeout(() => {
select.value?.setSelected(); tMagicSelect.value?.setSelected();
}, 0); }, 0);
} }
},
}; };
},
}); const itemOptions = options as Ref<SelectOption[]>;
const groupOptions = options as Ref<SelectGroupOption[]>;
</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,40 +1,42 @@
<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(() => { };
const activeValue = computed(() => {
if (typeof props.config.activeValue === 'undefined') { if (typeof props.config.activeValue === 'undefined') {
if (props.config.filter === 'number') { if (props.config.filter === 'number') {
return 1; return 1;
@ -44,8 +46,9 @@ export default defineComponent({
} }
return true; return true;
}), });
inactiveValue: computed(() => {
const inactiveValue = computed(() => {
if (typeof props.config.inactiveValue === 'undefined') { if (typeof props.config.inactiveValue === 'undefined') {
if (props.config.filter === 'number') { if (props.config.filter === 'number') {
return 0; return 0;
@ -55,11 +58,5 @@ export default defineComponent({
} }
return false; return false;
}),
changeHandler: (v: boolean | number | string) => {
emit('change', v);
},
};
},
}); });
</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,50 +20,45 @@
{{ 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'],
setup(props, { emit }) {
const mForm = inject<FormState | undefined>('mForm');
useAddField(props.prop); useAddField(props.prop);
const modelName = computed(() => props.name || props.config.name || ''); const mForm = inject<FormState | undefined>('mForm');
return {
modelName,
changeHandler(v: string | number) { const changeHandler = (value: number) => {
emit('change', v); emit('change', value);
}, };
inputHandler(v: string | number) { const inputHandler = (v: string) => {
emit('input', v); emit('input', v);
mForm?.$emit('field-input', props.prop, v); mForm?.$emit('field-input', props.prop, v);
}, };
buttonClickHandler() { const buttonClickHandler = () => {
if (typeof props.config.append === 'string') return; if (typeof props.config.append === 'string') return;
if (props.config.append?.handler) { if (props.config.append?.handler) {
@ -72,11 +67,11 @@ export default defineComponent({
values: mForm?.values, values: mForm?.values,
}); });
} }
}, };
keyUpHandler($event: KeyboardEvent) { const keyUpHandler = ($event: KeyboardEvent) => {
if (!props.model) return; if (!props.model) return;
if (!modelName.value) return; if (!props.name) return;
const arrowUp = $event.key === 'ArrowUp'; const arrowUp = $event.key === 'ArrowUp';
const arrowDown = $event.key === 'ArrowDown'; const arrowDown = $event.key === 'ArrowDown';
@ -85,7 +80,7 @@ export default defineComponent({
return; return;
} }
const value = props.model[modelName.value]; const value = props.model[props.name];
let num; let num;
let unit; let unit;
if (isNumber(value)) { if (isNumber(value)) {
@ -127,10 +122,7 @@ export default defineComponent({
} }
} }
props.model[modelName.value] = `${num}${unit || ''}`; props.model[props.name] = `${num}${unit || ''}`;
emit('change', props.model[modelName.value]); emit('change', props.model[props.name]);
},
}; };
},
});
</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) {
return values;
},
},
setup(props, { emit }) {
useAddField(props.prop); useAddField(props.prop);
const mForm = inject<FormState | null>('mForm'); const mForm = inject<FormState | null>('mForm');
return { const changeHandler = (value: number) => {
mForm, emit('change', value);
changeHandler: (v: string) => { };
emit('change', v);
},
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,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: {
change(values: Date) {
return values;
},
},
setup(props, { emit }) {
useAddField(props.prop); useAddField(props.prop);
return { const changeHandler = (v: string) => {
changeHandler: (v: Date) => {
emit('change', v); 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: {