1. 新增描述列表包装控件

2. 优化tooltip显示
3. 动态属性slots支持
This commit is contained in:
Gary Fu
2024-07-28 21:41:04 +08:00
parent 72060f67a5
commit b0ef42dc1d
7 changed files with 172 additions and 6 deletions

View File

@@ -78,7 +78,7 @@ const allMenus = [
{
id: 25,
parentId: 2,
iconCls: 'PieChartSharp',
iconCls: 'PieChart',
nameCn: '图表示例',
nameEn: 'Charts',
menuUrl: '/charts'

View File

@@ -0,0 +1,83 @@
<script setup>
import { calcSlotsResult, toLabelByKey } from '@/components/utils'
import { isFunction } from 'lodash-es'
import { isVNode, computed } from 'vue'
const props = defineProps({
items: {
type: Array,
default: () => []
},
width: {
type: String,
default: ''
},
minWidth: {
type: String,
default: ''
}
})
const calcItems = computed(() => {
return props.items.filter(item => item.enabled !== false).map(item => {
const label = item.labelKey ? toLabelByKey(item.labelKey) : item.label
const value = isFunction(item.formatter) ? item.formatter(item) : item.value
const valueResult = { value, vnode: isVNode(value) }
const slotsResult = calcSlotsResult(item)
return {
...item,
label,
width: item.width || props.width,
minWidth: item.minWidth || props.minWidth,
valueResult,
slotsResult
}
})
})
</script>
<template>
<el-descriptions
v-bind="$attrs"
>
<el-descriptions-item
v-for="(calcItem, index) in calcItems"
:key="index"
:label="calcItem.label"
:min-width="calcItem.minWidth"
:width="calcItem.width"
:span="calcItem.span"
:align="calcItem.align"
v-bind="calcItem.attrs"
>
<template
v-for="(slot, slotKey) in (calcItem.slots||{})"
:key="slotKey"
#[slotKey]
>
<component
:is="calcItem.slotsResult[slotKey].result"
v-if="calcItem.slotsResult[slotKey]?.vnode"
/>
<template v-else>
{{ calcItem.slotsResult[slotKey].result }}
</template>
</template>
<template v-if="calcItem.valueResult.value">
<span
v-if="calcItem.valueResult.value&&!calcItem.valueResult.vnode"
v-html="calcItem.valueResult.value"
/>
<component
:is="calcItem.valueResult.value"
v-if="calcItem.valueResult.vnode"
/>
</template>
</el-descriptions-item>
</el-descriptions>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,30 @@
import { VNode } from 'vue'
import { descriptionItemProps } from 'element-plus/es/components/descriptions/src/description-item'
export interface CommonDescriptionItem {
label?: string;
labelKey?: string;
value?: string;
span?: number;
width?: string;
minWidth?: string;
className?: string;
labelClassName?: string;
align?: 'left' | 'right' | 'center';
labelAlign?: string;
slots?: any;
formatter?: (item: CommonDescriptionItem) => string | VNode;
attrs?: descriptionItemProps;
}
export interface CommonDescriptionProps {
border?: boolean;
column?: number;
direction?: 'horizontal' | 'vertical';
size?: 'default' | 'small' | 'large';
title?: string;
extra?: string;
items?: Array<CommonDescriptionItem>;
width?: string;
minWidth?: string;
}

View File

@@ -48,11 +48,12 @@ const tooltipFunc = ($event) => {
{{ label }}
<el-tooltip
v-if="option.tooltip||option.tooltipFunc"
class="box-item"
class="box-item common-el-tooltip"
effect="dark"
:disabled="!option.tooltip"
:content="option.tooltip"
placement="top-start"
raw-content
>
<span>
<el-link

View File

@@ -222,6 +222,24 @@ const formatResult = computed(() => {
return null
})
const slotsResult = computed(() => {
const results = {}
if (calcOption.value?.slots) {
const slots = calcOption.value.slots
for (const slotKey in slots) {
const slot = slots[slotKey]
if (isFunction(slot)) {
const slotResult = slot(modelValue.value, calcOption.value)
results[slotKey] = {
result: slotResult,
vnode: isVNode(slotResult)
}
}
}
}
return results
})
</script>
<template>
@@ -252,11 +270,12 @@ const formatResult = computed(() => {
<slot name="afterLabel" />
<el-tooltip
v-if="calcOption.tooltip||calcOption.tooltipFunc"
class="box-item"
class="box-item common-el-tooltip"
effect="dark"
:disabled="!calcOption.tooltip"
:content="calcOption.tooltip"
placement="top-start"
raw-content
>
<span>
<el-link
@@ -280,6 +299,19 @@ const formatResult = computed(() => {
:readonly="calcOption.readonly"
@change="controlChange"
>
<template
v-for="(slot, slotKey) in (calcOption.slots||{})"
:key="slotKey"
#[slotKey]
>
<component
:is="slotsResult[slotKey].result"
v-if="slotsResult[slotKey]?.vnode"
/>
<template v-else>
{{ slotsResult[slotKey].result }}
</template>
</template>
<template
v-if="hasModelText&&formatResult"
#default

View File

@@ -15,6 +15,7 @@ import CommonBreadcrumb from '@/components/common-breadcrumb/index.vue'
import CommonWindow from '@/components/common-window/index.vue'
import CommonAutocomplete from '@/components/common-autocomplete/index.vue'
import CommonSort from '@/components/common-sort/index.vue'
import CommonDescriptions from '@/components/common-descriptions/index.vue'
import CommonDirectives from '@/components/directives'
/**
@@ -42,6 +43,7 @@ export default {
Vue.component('CommonWindow', CommonWindow)
Vue.component('CommonAutocomplete', CommonAutocomplete)
Vue.component('CommonSort', CommonSort)
Vue.component('CommonDescriptions', CommonDescriptions)
Vue.use(CommonDirectives)
}
}

View File

@@ -1,4 +1,4 @@
import { ref, unref } from 'vue'
import { isVNode, ref, unref } from 'vue'
import { $i18nBundle, $i18nKey } from '@/messages'
import { isArray, isFunction, isObject } from 'lodash-es'
@@ -64,8 +64,8 @@ export const useMenuName = item => {
return toLabelByKey(menuInfo.labelKey)
}
}
if (item.meta && item.meta.labelKey) {
return toLabelByKey(item.meta.labelKey)
if (item.meta && (item.meta.label || item.meta.labelKey)) {
return item.meta.label || toLabelByKey(item.meta.labelKey)
}
return item.name || 'No Name'
}
@@ -154,6 +154,24 @@ export const proxyMethod = (targets = [], methodName) => {
}
}
export const calcSlotsResult = (config, data) => {
const results = {}
if (config?.slots) {
const slots = config.slots
for (const slotKey in slots) {
const slot = slots[slotKey]
if (isFunction(slot)) {
const slotResult = slot(data, config)
results[slotKey] = {
result: slotResult,
vnode: isVNode(slotResult)
}
}
}
}
return results
}
/**
* 定义表单选项带有jsdoc注解方便代码提示
* @param {CommonFormOption|CommonFormOption[]} formOptions 表单选项