mirror of
https://github.com/fugary/simple-element-plus-template.git
synced 2025-11-12 14:27:49 +00:00
1. 新增描述列表包装控件
2. 优化tooltip显示 3. 动态属性slots支持
This commit is contained in:
@@ -78,7 +78,7 @@ const allMenus = [
|
||||
{
|
||||
id: 25,
|
||||
parentId: 2,
|
||||
iconCls: 'PieChartSharp',
|
||||
iconCls: 'PieChart',
|
||||
nameCn: '图表示例',
|
||||
nameEn: 'Charts',
|
||||
menuUrl: '/charts'
|
||||
|
||||
83
src/components/common-descriptions/index.vue
Normal file
83
src/components/common-descriptions/index.vue
Normal 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>
|
||||
30
src/components/common-descriptions/public.d.ts
vendored
Normal file
30
src/components/common-descriptions/public.d.ts
vendored
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 表单选项
|
||||
|
||||
Reference in New Issue
Block a user