feat(design, form, tdesign-vue-next-adapter): 完善tdesign适配

This commit is contained in:
roymondchen 2025-10-23 19:56:57 +08:00
parent 68c69ac405
commit ca0f8fc988
9 changed files with 189 additions and 37 deletions

View File

@ -39,5 +39,9 @@ const clickHandler = (...args: any[]) => {
.t-button__text {
align-items: center;
}
+ .tmagic-design-button {
margin-left: 12px;
}
}
</style>

View File

@ -7,6 +7,7 @@
@change="changeHandler"
@input="inputHandler"
@update:modelValue="updateModelValue"
@blur="blurHandler"
>
<template #prepend v-if="$slots.prepend">
<slot name="prepend"></slot>
@ -41,7 +42,7 @@ const uiComponent = ui?.component || 'el-input';
const uiProps = computed<InputProps>(() => ui?.props(props) || props);
const emit = defineEmits(['change', 'input', 'update:modelValue']);
const emit = defineEmits(['change', 'input', 'blur', 'update:modelValue']);
const instance = ref<any>();
@ -57,13 +58,52 @@ const updateModelValue = (...args: any[]) => {
emit('update:modelValue', ...args);
};
const blurHandler = (...args: any[]) => {
emit('blur', ...args);
};
defineExpose({
instance,
getInput() {
return instance.value.input;
if (instance.value.input) {
return instance.value.input;
}
return instance.value?.$el?.querySelector('input');
},
getTextarea() {
return instance.value.textarea;
if (instance.value.textarea) {
return instance.value.textarea;
}
return instance.value?.$el?.querySelector('textarea');
},
});
</script>
<style lang="scss">
.tmagic-design-input {
&.t-input-adornment {
.t-input-adornment__prepend {
> span {
border-radius: var(--td-radius-default) 0 0 var(--td-radius-default);
}
}
.t-input-adornment__append {
> span {
border-radius: 0 var(--td-radius-default) var(--td-radius-default) 0;
}
}
.t-input-adornment__prepend,
.t-input-adornment__append {
> span {
display: inline-flex;
height: 100%;
align-items: center;
box-sizing: border-box;
white-space: nowrap;
padding: 0 var(--td-comp-paddingLR-s);
border: 1px solid var(--td-border-level-2-color);
}
}
}
}
</style>

View File

@ -8,6 +8,9 @@
@tab-remove="onTabRemove"
@update:model-value="updateModelName"
>
<template #add-icon v-if="$slots['add-icon']">
<slot name="add-icon"></slot>
</template>
<template #default>
<slot></slot>
</template>

View File

@ -32,6 +32,7 @@ export interface ButtonProps {
text?: boolean;
circle?: boolean;
icon?: any;
variant?: string;
}
export interface CardProps {
@ -193,6 +194,7 @@ export interface InputProps {
rows?: number;
type?: string;
size?: FieldSize;
row?: number;
}
export interface InputNumberProps {
@ -354,7 +356,7 @@ export interface TabPaneProps {
export interface TabsProps {
type?: string;
editable?: boolean;
tabPosition?: string;
tabPosition?: 'left' | 'right' | 'top' | 'bottom';
modelValue?: string | number;
}

View File

@ -167,7 +167,17 @@ watchEffect(() => {
const tabItems = (tab: TabPaneConfig) => (props.config.dynamic ? props.config.items : tab.items);
const tabClickHandler = (tab: any) => tabClick(mForm, tab, props);
const tabClickHandler = (tab: any) => {
if (typeof tab === 'object') {
tabClick(mForm, tab, props);
} else {
let item = tabs.value.find((tab: any) => tab.status === tab);
if (!item) {
item = tabs.value[tab];
}
tabClick(mForm, item, props);
}
};
const onTabAdd = async () => {
if (!props.name) throw new Error('dynamic tab 必须配置name');

View File

@ -48,4 +48,8 @@
margin-left: 0 !important;
}
}
&.t-form:not(.t-form-inline) .t-form__item:last-of-type {
margin-bottom: var(--td-comp-margin-xxl);
}
}

View File

@ -5,34 +5,46 @@
:size="size === 'default' ? 'medium' : size"
:disabled="disabled"
:placeholder="placeholder"
:row="row"
@keypress="inputHandler"
@change="changeHandler"
></TTextarea>
<TInput
v-else
:modelValue="modelValue"
:size="size === 'default' ? 'medium' : size"
:clearable="clearable"
:disabled="disabled"
:placeholder="placeholder"
@keypress="inputHandler"
@change="changeHandler"
@update:modelValue="updateModelValue"
>
<template #prefix-icon v-if="$slots.prefix">
<slot name="prefix"></slot>
<TInputAdornment v-else>
<template #prepend v-if="$slots.prepend">
<slot name="prepend"></slot>
</template>
<template #suffix v-if="$slots.suffix">
<slot name="suffix"></slot>
<template #append v-if="$slots.append">
<slot name="append"></slot>
</template>
</TInput>
<TInput
:modelValue="modelValue"
:size="size === 'default' ? 'medium' : size"
:clearable="clearable"
:disabled="disabled"
:placeholder="placeholder"
@keypress="inputHandler"
@change="changeHandler"
@update:modelValue="updateModelValue"
>
<template #prefix-icon v-if="$slots.prefix">
<slot name="prefix"></slot>
</template>
<template #suffix v-if="$slots.suffix">
<slot name="suffix"></slot>
</template>
</TInput>
</TInputAdornment>
</template>
<script lang="ts" setup>
import { Input as TInput, Textarea as TTextarea } from 'tdesign-vue-next';
import { Input as TInput, InputAdornment as TInputAdornment, Textarea as TTextarea } from 'tdesign-vue-next';
import type { InputProps } from '@tmagic/design';
defineOptions({
name: 'TTDesignAdapterInput',
});
defineProps<
InputProps & {
modelValue: string;

View File

@ -0,0 +1,49 @@
<template>
<TTabs
:model-value="modelValue"
:addable="editable"
:theme="type === 'card' ? 'card' : 'normal'"
:placement="tabPosition"
@add="onTabAdd"
@change="tabClickHandler"
@remove="onTabRemove"
@update:model-value="updateModelName"
>
<template #action v-if="$slots['add-icon']">
<slot name="add-icon"></slot>
</template>
<template #default>
<slot></slot>
</template>
</TTabs>
</template>
<script setup lang="ts">
import { Tabs as TTabs } from 'tdesign-vue-next';
import type { TabsProps } from '@tmagic/design';
defineOptions({
name: 'TTDesignAdapterTabs',
});
defineProps<TabsProps>();
const emit = defineEmits(['tab-click', 'tab-add', 'tab-remove', 'update:model-value']);
const tabClickHandler = (...args: any[]) => {
emit('tab-click', ...args);
};
const onTabAdd = (...args: any[]) => {
emit('tab-add', ...args);
};
const onTabRemove = (...args: any[]) => {
emit('tab-remove', ...args);
};
const updateModelName = (...args: any[]) => {
emit('update:model-value', ...args);
};
</script>

View File

@ -17,6 +17,7 @@ import {
Form as TForm,
FormItem as TFormItem,
InputNumber as TInputNumber,
LoadingDirective,
MessagePlugin,
Option as TOption,
OptionGroup as TOptionGroup,
@ -28,7 +29,6 @@ import {
Steps as TSteps,
Switch as TSwitch,
TabPanel as TTabPanel,
Tabs as TTabs,
Tag as TTag,
TimePicker as TTimePicker,
Tooltip as TTooltip,
@ -59,6 +59,7 @@ import type {
OptionGroupProps,
OptionProps,
PaginationProps,
PopconfirmProps,
RadioButtonProps,
RadioGroupProps,
RadioProps,
@ -80,22 +81,46 @@ import DatePicker from './DatePicker.vue';
import Dialog from './Dialog.vue';
import Icon from './Icon.vue';
import Input from './Input.vue';
import Popconfirm from './Popconfirm.vue';
import Radio from './Radio.vue';
import RadioButton from './RadioButton.vue';
import Scrollbar from './Scrollbar.vue';
import Table from './Table.vue';
import Tabs from './Tabs.vue';
const adapter: any = {
message: MessagePlugin,
messageBox: {
alert: (msg: string) => {
DialogPlugin.alert({
body: msg,
alert: (msg: string, title?: string) => {
return new Promise((resolve, reject) => {
const dia = DialogPlugin.alert({
header: title,
body: msg,
onConfirm: (e) => {
dia.hide();
resolve(e);
},
onClose: (e) => {
dia.hide();
reject(e);
},
});
});
},
confirm: (msg: string) => {
DialogPlugin.confirm({
body: msg,
confirm: (msg: string, title?: string) => {
return new Promise((resolve, reject) => {
const dia = DialogPlugin.confirm({
header: title,
body: msg,
onConfirm: (e) => {
dia.hide();
resolve(e);
},
onClose: (e) => {
dia.hide();
reject(e);
},
});
});
},
close: (msg: string) => {
@ -118,7 +143,7 @@ const adapter: any = {
theme: props.type,
size: props.size === 'default' ? 'medium' : props.size,
icon: props.icon ? () => h(Icon, null, { default: () => h(props.icon) }) : undefined,
variant: props.link || props.text ? 'text' : 'base',
variant: props.link || props.text ? 'text' : props.variant || 'base',
shape: props.circle ? 'circle' : 'rectangle',
}),
},
@ -129,6 +154,8 @@ const adapter: any = {
shadow: props.shadow !== 'never',
hoverShadow: props.shadow === 'hover',
header: props.header,
bodyStyle: props.bodyStyle,
headerBordered: true,
}),
},
@ -419,13 +446,8 @@ const adapter: any = {
},
tabs: {
component: TTabs,
props: (props: TabsProps) => ({
addable: props.editable,
theme: props.type === 'card' ? 'card' : 'normal',
placement: props.tabPosition,
value: props.modelValue,
}),
component: Tabs,
props: (props: TabsProps) => props,
},
tag: {
@ -462,7 +484,13 @@ const adapter: any = {
autoUpload: props.autoUpload,
}),
},
popconfirm: {
component: Popconfirm,
props: (props: PopconfirmProps) => props,
},
},
loading: LoadingDirective,
};
export default adapter;