mirror of
https://gitee.com/dapppp/ruoyi-plus-vben5.git
synced 2026-03-21 03:08:57 +08:00
feat: 字典(DictTag)支持fallback属性(未匹配到字典项时的回显)
This commit is contained in:
@@ -5,10 +5,12 @@
|
|||||||
- 流程表达式 follow后端更新
|
- 流程表达式 follow后端更新
|
||||||
- websocket功能(默认关闭)
|
- websocket功能(默认关闭)
|
||||||
- useVbenForm 增加 TimeRangePicker(时间区间选择) 组件
|
- useVbenForm 增加 TimeRangePicker(时间区间选择) 组件
|
||||||
|
- 字典(DictTag)支持fallback属性(未匹配到字典项时的回显)
|
||||||
|
|
||||||
**REFACTOR**
|
**REFACTOR**
|
||||||
|
|
||||||
- Modal/Drawer中使用VxeTable tooltip需要设置更高的z-index 防止被遮挡
|
- Modal/Drawer中使用VxeTable tooltip需要设置更高的z-index 防止被遮挡
|
||||||
|
- 字典(DictTag)使用tsx写法重构
|
||||||
|
|
||||||
**OTHERS**
|
**OTHERS**
|
||||||
|
|
||||||
|
|||||||
@@ -1,62 +1,134 @@
|
|||||||
<!-- eslint-disable eqeqeq -->
|
<!-- 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 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 { Spin, Tag } from 'ant-design-vue';
|
||||||
|
import { isFunction, isString } from 'lodash-es';
|
||||||
|
|
||||||
import { tagTypes } from './data';
|
import { tagTypes } from './data';
|
||||||
|
|
||||||
interface Props {
|
/**
|
||||||
dicts: DictData[]; // dict数组
|
* 使用tsx重构原来的template写法
|
||||||
value: number | string; // value
|
* 在大量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>(), {
|
const cssClass = computed<string>(() => {
|
||||||
dicts: undefined,
|
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);
|
* 返回null 走 fallback逻辑
|
||||||
const listClass = current?.listClass ?? '';
|
*/
|
||||||
// 是否为默认的颜色
|
const label = computed<null | string>(() => {
|
||||||
const isDefault = Reflect.has(tagTypes, listClass);
|
const current = props.dicts.find((item) => item.dictValue == props.value);
|
||||||
// 判断是默认还是自定义颜色
|
return current?.dictLabel ?? null;
|
||||||
if (isDefault) {
|
});
|
||||||
// 这里做了antd - element-plus的兼容
|
|
||||||
return tagTypes[listClass]!.color;
|
|
||||||
}
|
|
||||||
return listClass;
|
|
||||||
});
|
|
||||||
|
|
||||||
const cssClass = computed<string>(() => {
|
const loading = computed(() => {
|
||||||
const current = props.dicts.find((item) => item.dictValue == props.value);
|
return props.dicts?.length === 0;
|
||||||
return current?.cssClass ?? '';
|
});
|
||||||
});
|
|
||||||
|
|
||||||
const label = computed<number | string>(() => {
|
return {
|
||||||
const current = props.dicts.find((item) => item.dictValue == props.value);
|
color,
|
||||||
return current?.dictLabel ?? 'unknown';
|
cssClass,
|
||||||
});
|
label,
|
||||||
|
loading,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
const { color, cssClass, label, loading, fallback, value } = this;
|
||||||
|
|
||||||
const tagComponent = computed(() => (color.value ? Tag : 'div'));
|
/**
|
||||||
|
* 字典list为0 加载中
|
||||||
|
*/
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Spin size="small" spinning />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const loading = computed(() => {
|
/**
|
||||||
return props.dicts?.length === 0;
|
* 没有匹配到字典(label === null)的fallback
|
||||||
|
* 可为string/Vnode
|
||||||
|
*/
|
||||||
|
if (label === null) {
|
||||||
|
// VNode
|
||||||
|
if (isFunction(fallback)) {
|
||||||
|
return h(fallback(value));
|
||||||
|
}
|
||||||
|
// 默认显示 unknown 文案
|
||||||
|
if (isString(fallback)) {
|
||||||
|
return <div>{fallback}</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 有color 属性 渲染Tag
|
||||||
|
*/
|
||||||
|
if (color) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Tag class={cssClass} color={color}>
|
||||||
|
{label}
|
||||||
|
</Tag>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div class={cssClass}>{label}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<component
|
|
||||||
v-if="!loading"
|
|
||||||
:is="tagComponent"
|
|
||||||
:class="cssClass"
|
|
||||||
:color="color"
|
|
||||||
>
|
|
||||||
{{ label }}
|
|
||||||
</component>
|
|
||||||
<Spin v-else :spinning="true" size="small" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|||||||
5
apps/web-antd/src/components/dict/src/type.d.ts
vendored
Normal file
5
apps/web-antd/src/components/dict/src/type.d.ts
vendored
Normal file
@@ -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 { Component as ComponentType } from 'vue';
|
||||||
|
|
||||||
import type { DictData } from '#/api/system/dict/dict-data-model';
|
import type { DictData } from '#/api/system/dict/dict-data-model';
|
||||||
|
import type { DictFallback } from '#/components/dict/src/type';
|
||||||
|
|
||||||
import { h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
@@ -149,16 +150,26 @@ export function renderDictTags(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RenderDictOptions {
|
||||||
|
fallback?: DictFallback;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 显示字典标签 一般是table使用
|
* 显示字典标签 一般是table使用
|
||||||
* @param value 值
|
* @param value 值
|
||||||
* @param dictName dictName
|
* @param dictName dictName
|
||||||
* @returns tag
|
* @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);
|
const dictInfo = getDictOptions(dictName);
|
||||||
return renderDictTag(value, dictInfo);
|
return <DictTag dicts={dictInfo} fallback={fallback} value={value}></DictTag>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderIconSpan(
|
export function renderIconSpan(
|
||||||
icon: ComponentType,
|
icon: ComponentType,
|
||||||
value: string,
|
value: string,
|
||||||
|
|||||||
Reference in New Issue
Block a user