feat: Add Descriptions component and add Descriptions demo
parent
af9fc0a4ad
commit
7ad46f828d
@ -0,0 +1,3 @@
|
|||||||
|
import Descriptions from './src/Descriptions.vue'
|
||||||
|
|
||||||
|
export { Descriptions }
|
||||||
@ -0,0 +1,134 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ElCollapseTransition, ElDescriptions, ElDescriptionsItem, ElTooltip } from 'element-plus'
|
||||||
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
import { ref, unref, PropType, computed, useAttrs } from 'vue'
|
||||||
|
import { useAppStore } from '@/store/modules/app'
|
||||||
|
|
||||||
|
const appStore = useAppStore()
|
||||||
|
|
||||||
|
const mobile = computed(() => appStore.getMobile)
|
||||||
|
|
||||||
|
const attrs = useAttrs()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
title: propTypes.string.def(''),
|
||||||
|
message: propTypes.string.def(''),
|
||||||
|
collapse: propTypes.bool.def(true),
|
||||||
|
schema: {
|
||||||
|
type: Array as PropType<DescriptionsSchema[]>,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Object as PropType<Recordable>,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const { getPrefixCls } = useDesign()
|
||||||
|
|
||||||
|
const prefixCls = getPrefixCls('descriptions')
|
||||||
|
|
||||||
|
const getBindValue = computed(() => {
|
||||||
|
const delArr: string[] = ['title', 'message', 'collapse', 'schema', 'data', 'class']
|
||||||
|
const obj = { ...attrs, ...props }
|
||||||
|
for (const key in obj) {
|
||||||
|
if (delArr.indexOf(key) !== -1) {
|
||||||
|
delete obj[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
})
|
||||||
|
|
||||||
|
const getBindItemValue = (item: DescriptionsSchema) => {
|
||||||
|
const delArr: string[] = ['field']
|
||||||
|
const obj = { ...item }
|
||||||
|
for (const key in obj) {
|
||||||
|
if (delArr.indexOf(key) !== -1) {
|
||||||
|
delete obj[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
// 折叠
|
||||||
|
const show = ref(true)
|
||||||
|
|
||||||
|
const toggleClick = () => {
|
||||||
|
if (props.collapse) {
|
||||||
|
show.value = !unref(show)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="[prefixCls, 'bg-[var(--el-color-white)]']">
|
||||||
|
<div
|
||||||
|
v-if="title"
|
||||||
|
:class="[
|
||||||
|
`${prefixCls}-header`,
|
||||||
|
'h-50px flex justify-between items-center mb-10px border-bottom-1 border-solid border-[var(--tags-view-border-color)] px-10px cursor-pointer'
|
||||||
|
]"
|
||||||
|
@click="toggleClick"
|
||||||
|
>
|
||||||
|
<div :class="[`${prefixCls}-header__title`, 'relative font-18px font-bold ml-10px']">
|
||||||
|
<div class="flex items-center">
|
||||||
|
{{ title }}
|
||||||
|
<ElTooltip v-if="message" :content="message" placement="right">
|
||||||
|
<Icon icon="ep:warning" class="ml-5px" />
|
||||||
|
</ElTooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Icon v-if="collapse" :icon="show ? 'ep:arrow-down' : 'ep:arrow-up'" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ElCollapseTransition>
|
||||||
|
<div v-show="show" :class="[`${prefixCls}-content`, 'p-10px']">
|
||||||
|
<ElDescriptions
|
||||||
|
:column="2"
|
||||||
|
border
|
||||||
|
:direction="mobile ? 'vertical' : 'horizontal'"
|
||||||
|
v-bind="getBindValue"
|
||||||
|
>
|
||||||
|
<ElDescriptionsItem
|
||||||
|
v-for="item in schema"
|
||||||
|
:key="item.field"
|
||||||
|
v-bind="getBindItemValue(item)"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<slot :name="`${item.field}-label`" :label="item.label">{{ item.label }}</slot>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #default>
|
||||||
|
<slot :name="item.field">{{ data[item.field] }}</slot>
|
||||||
|
</template>
|
||||||
|
</ElDescriptionsItem>
|
||||||
|
</ElDescriptions>
|
||||||
|
</div>
|
||||||
|
</ElCollapseTransition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@prefix-cls: ~'@{namespace}-descriptions';
|
||||||
|
|
||||||
|
.@{prefix-cls}-header {
|
||||||
|
&__title {
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: -10px;
|
||||||
|
width: 4px;
|
||||||
|
height: 70%;
|
||||||
|
background: var(--el-color-primary);
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.@{prefix-cls}-content {
|
||||||
|
:deep(.@{elNamespace}-descriptions__cell) {
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,32 +0,0 @@
|
|||||||
import { PropType } from 'vue'
|
|
||||||
|
|
||||||
export const imageViewerProps = {
|
|
||||||
urlList: {
|
|
||||||
type: Array as PropType<string[]>,
|
|
||||||
default: (): string[] => []
|
|
||||||
},
|
|
||||||
zIndex: {
|
|
||||||
type: Number as PropType<number>,
|
|
||||||
default: 2000
|
|
||||||
},
|
|
||||||
initialIndex: {
|
|
||||||
type: Number as PropType<number>,
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
infinite: {
|
|
||||||
type: Boolean as PropType<boolean>,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
hideOnClickModal: {
|
|
||||||
type: Boolean as PropType<boolean>,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
appendToBody: {
|
|
||||||
type: Boolean as PropType<boolean>,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
show: {
|
|
||||||
type: Boolean as PropType<boolean>,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,140 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Descriptions } from '@/components/Descriptions'
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
import { reactive, unref } from 'vue'
|
||||||
|
import { Form } from '@/components/Form'
|
||||||
|
import { ElFormItem, ElInput, ElButton } from 'element-plus'
|
||||||
|
import { required } from '@/utils/formRules'
|
||||||
|
import { useForm } from '@/hooks/web/useForm'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
username: 'chenkl',
|
||||||
|
nickName: '梦似花落。',
|
||||||
|
age: 26,
|
||||||
|
phone: '13655971xxxx',
|
||||||
|
email: '502431556@qq.com',
|
||||||
|
addr: '这是一个很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长的地址',
|
||||||
|
sex: '男',
|
||||||
|
certy: '3505831994xxxxxxxx'
|
||||||
|
})
|
||||||
|
|
||||||
|
const schema = reactive<DescriptionsSchema[]>([
|
||||||
|
{
|
||||||
|
field: 'username',
|
||||||
|
label: t('descriptionsDemo.username')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'nickName',
|
||||||
|
label: t('descriptionsDemo.nickName')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'phone',
|
||||||
|
label: t('descriptionsDemo.phone')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'email',
|
||||||
|
label: t('descriptionsDemo.email')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'addr',
|
||||||
|
label: t('descriptionsDemo.addr'),
|
||||||
|
span: 24
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const form = reactive({
|
||||||
|
username: '',
|
||||||
|
nickName: '',
|
||||||
|
phone: '',
|
||||||
|
email: '',
|
||||||
|
addr: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const rules = reactive({
|
||||||
|
username: [required],
|
||||||
|
nickName: [required],
|
||||||
|
phone: [required],
|
||||||
|
email: [required],
|
||||||
|
addr: [required]
|
||||||
|
})
|
||||||
|
|
||||||
|
const { register, elFormRef } = useForm()
|
||||||
|
|
||||||
|
const formValidation = () => {
|
||||||
|
unref(elFormRef)
|
||||||
|
?.validate()
|
||||||
|
?.catch(() => {})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Descriptions
|
||||||
|
:title="t('descriptionsDemo.descriptions')"
|
||||||
|
:message="t('descriptionsDemo.descriptionsDes')"
|
||||||
|
:data="data"
|
||||||
|
:schema="schema"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Form is-custom :model="form" :rules="rules" @register="register">
|
||||||
|
<Descriptions :title="t('descriptionsDemo.form')" :data="data" :schema="schema" class="mt-20px">
|
||||||
|
<template #username-label="scope">
|
||||||
|
<span class="is-required--item">{{ scope.label }}</span>
|
||||||
|
</template>
|
||||||
|
<template #nickName-label="scope">
|
||||||
|
<span class="is-required--item">{{ scope.label }}</span>
|
||||||
|
</template>
|
||||||
|
<template #phone-label="scope">
|
||||||
|
<span class="is-required--item">{{ scope.label }}</span>
|
||||||
|
</template>
|
||||||
|
<template #email-label="scope">
|
||||||
|
<span class="is-required--item">{{ scope.label }}</span>
|
||||||
|
</template>
|
||||||
|
<template #addr-label="scope">
|
||||||
|
<span class="is-required--item">{{ scope.label }}</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #username>
|
||||||
|
<ElFormItem prop="username">
|
||||||
|
<ElInput v-model="form.username" />
|
||||||
|
</ElFormItem>
|
||||||
|
</template>
|
||||||
|
<template #nickName>
|
||||||
|
<ElFormItem prop="nickName">
|
||||||
|
<ElInput v-model="form.nickName" />
|
||||||
|
</ElFormItem>
|
||||||
|
</template>
|
||||||
|
<template #phone>
|
||||||
|
<ElFormItem prop="phone">
|
||||||
|
<ElInput v-model="form.phone" />
|
||||||
|
</ElFormItem>
|
||||||
|
</template>
|
||||||
|
<template #email>
|
||||||
|
<ElFormItem prop="email">
|
||||||
|
<ElInput v-model="form.email" />
|
||||||
|
</ElFormItem>
|
||||||
|
</template>
|
||||||
|
<template #addr>
|
||||||
|
<ElFormItem prop="addr">
|
||||||
|
<ElInput v-model="form.addr" />
|
||||||
|
</ElFormItem>
|
||||||
|
</template>
|
||||||
|
</Descriptions>
|
||||||
|
<div class="text-center mt-10px">
|
||||||
|
<ElButton @click="formValidation"> {{ t('formDemo.formValidation') }} </ElButton>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.is-required--item {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
margin-right: 4px;
|
||||||
|
color: var(--el-color-danger);
|
||||||
|
content: '*';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
declare interface DescriptionsSchema {
|
||||||
|
span?: number // 占多少分
|
||||||
|
field: string // 字段名
|
||||||
|
label?: string // label名
|
||||||
|
width?: string | number
|
||||||
|
minWidth?: string | number
|
||||||
|
align?: 'left' | 'center' | 'right'
|
||||||
|
labelAlign?: 'left' | 'center' | 'right'
|
||||||
|
className?: string
|
||||||
|
labelClassName?: string
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue