feat: 字典(DictTag)支持fallback属性(未匹配到字典项时的回显)

master
dap 5 months ago
parent 253c9b5248
commit 808406ebce

@ -5,10 +5,12 @@
- 流程表达式 follow后端更新
- websocket功能(默认关闭)
- useVbenForm 增加 TimeRangePicker(时间区间选择) 组件
- 字典(DictTag)支持fallback属性(未匹配到字典项时的回显)
**REFACTOR**
- Modal/Drawer中使用VxeTable tooltip需要设置更高的z-index 防止被遮挡
- 字典(DictTag)使用tsx写法重构
**OTHERS**

@ -1,62 +1,134 @@
<!-- eslint-disable eqeqeq -->
<script setup lang="ts">
<script lang="tsx">
import type { PropType } from 'vue';
import type { DictFallback } from './type';
import type { DictData } from '#/api/system/dict/dict-data-model';
import { computed } from 'vue';
import { computed, defineComponent, h } from 'vue';
import { Spin, Tag } from 'ant-design-vue';
import { isFunction, isString } from 'lodash-es';
import { tagTypes } from './data';
interface Props {
dicts: DictData[]; // dict
value: number | string; // value
}
/**
* 使用tsx重构原来的template写法
* 在大量if的情况 tsx比template的v-if好用得多
*/
export default defineComponent({
name: 'DictTag',
props: {
/**
* 字典项options
*/
dicts: {
required: false,
type: Array as PropType<DictData[]>,
default: () => [],
},
/**
* 当前值
*/
value: {
required: true,
type: [Number, String],
},
/**
* 未匹配到字典项的fallback
*/
fallback: {
required: false,
type: [String, Function] as PropType<DictFallback>,
default: 'unknown',
},
},
setup(props) {
const color = computed<string>(() => {
const current = props.dicts.find((item) => item.dictValue == props.value);
const listClass = current?.listClass ?? '';
//
const isDefault = Reflect.has(tagTypes, listClass);
//
if (isDefault) {
// antd - element-plus
return tagTypes[listClass]!.color;
}
return listClass;
});
const props = withDefaults(defineProps<Props>(), {
dicts: undefined,
});
const cssClass = computed<string>(() => {
const current = props.dicts.find((item) => item.dictValue == props.value);
return current?.cssClass ?? '';
});
const color = computed<string>(() => {
const current = props.dicts.find((item) => item.dictValue == props.value);
const listClass = current?.listClass ?? '';
//
const isDefault = Reflect.has(tagTypes, listClass);
//
if (isDefault) {
// antd - element-plus
return tagTypes[listClass]!.color;
}
return listClass;
});
/**
* 返回null fallback逻辑
*/
const label = computed<null | string>(() => {
const current = props.dicts.find((item) => item.dictValue == props.value);
return current?.dictLabel ?? null;
});
const cssClass = computed<string>(() => {
const current = props.dicts.find((item) => item.dictValue == props.value);
return current?.cssClass ?? '';
});
const loading = computed(() => {
return props.dicts?.length === 0;
});
const label = computed<number | string>(() => {
const current = props.dicts.find((item) => item.dictValue == props.value);
return current?.dictLabel ?? 'unknown';
});
return {
color,
cssClass,
label,
loading,
};
},
render() {
const { color, cssClass, label, loading, fallback, value } = this;
/**
* 字典list为0 加载中
*/
if (loading) {
return (
<div>
<Spin size="small" spinning />
</div>
);
}
const tagComponent = computed(() => (color.value ? Tag : 'div'));
/**
* 没有匹配到字典label === null的fallback
* 可为string/Vnode
*/
if (label === null) {
// VNode
if (isFunction(fallback)) {
return h(fallback(value));
}
// unknown
if (isString(fallback)) {
return <div>{fallback}</div>;
}
}
const loading = computed(() => {
return props.dicts?.length === 0;
/**
* 有color 属性 渲染Tag
*/
if (color) {
return (
<div>
<Tag class={cssClass} color={color}>
{label}
</Tag>
</div>
);
}
return (
<div>
<div class={cssClass}>{label}</div>
</div>
);
},
});
</script>
<template>
<div>
<component
v-if="!loading"
:is="tagComponent"
:class="cssClass"
:color="color"
>
{{ label }}
</component>
<Spin v-else :spinning="true" size="small" />
</div>
</template>

@ -0,0 +1,5 @@
/**
* fallback
* /Vnode
*/
export type DictFallback = ((current: number | string) => VNode) | string;

@ -1,6 +1,7 @@
import type { Component as ComponentType } from 'vue';
import type { DictData } from '#/api/system/dict/dict-data-model';
import type { DictFallback } from '#/components/dict/src/type';
import { h } from 'vue';
@ -149,16 +150,26 @@ export function renderDictTags(
);
}
export interface RenderDictOptions {
fallback?: DictFallback;
}
/**
* table使
* @param value
* @param dictName dictName
* @returns tag
*/
export function renderDict(value: number | string, dictName: string) {
export function renderDict(
value: number | string,
dictName: string,
options?: RenderDictOptions,
) {
const { fallback } = options ?? {};
const dictInfo = getDictOptions(dictName);
return renderDictTag(value, dictInfo);
return <DictTag dicts={dictInfo} fallback={fallback} value={value}></DictTag>;
}
export function renderIconSpan(
icon: ComponentType,
value: string,

Loading…
Cancel
Save