This commit is contained in:
guochunsi
2026-01-06 16:39:57 +08:00
parent 7f91263205
commit 9e583c3c30
32 changed files with 2830 additions and 481 deletions

View File

@@ -0,0 +1,149 @@
# StatusTag 组件
状态标签组件,用于显示状态值对应的标签文本,支持自定义样式和颜色。
## 功能特性
- ✅ 支持标签样式和纯文本样式两种显示模式
- ✅ 支持自定义类型映射typeMap和颜色映射colorMap
- ✅ 内置默认样式('1' → warning/dark'0' → primary/light
- ✅ 外部传入优先,支持覆盖默认样式
## Props
| 参数 | 说明 | 类型 | 默认值 | 必填 |
|------|------|------|--------|------|
| value | 当前状态值 | `string \| number` | `''` | 是 |
| options | 选项列表,格式:`[{label: '是', value: '1'}, {label: '否', value: '0'}]` | `Option[]` | `[]` | 是 |
| showTag | 是否显示标签样式(有边框和背景),`false` 为纯文本样式 | `boolean` | `true` | 否 |
| typeMap | 自定义类型映射,用于标签模式,如:`{'1': {type: 'warning', effect: 'dark'}}` | `Record<string \| number, { type: string; effect?: string }>` | `{}` | 否 |
| colorMap | 自定义颜色映射,用于纯文本模式,如:`{'1': '#E6A23C'}` | `Record<string \| number, string>` | `{}` | 否 |
### Option 接口
```typescript
interface Option {
label: string // 显示文本
value: string | number // 选项值
}
```
## 默认样式
组件内置了默认的样式映射,无需传入 `typeMap``colorMap` 即可使用:
- **值 '1' 或 1**
- 标签模式:`warning` 类型 + `dark` 效果(橙色深色)
- 纯文本模式:`var(--el-color-warning)`(橙色)
- **值 '0' 或 0**
- 标签模式:`primary` 类型 + `light` 效果(蓝色浅色)
- 纯文本模式:`var(--el-color-primary)`(蓝色)
- **其他值**
- 标签模式:`info` 类型 + `light` 效果(灰色)
- 纯文本模式:默认文本颜色
## 使用示例
### 基础用法
```vue
<template>
<StatusTag
:value="scope.row.tied"
:options="YES_OR_NO"
/>
</template>
<script setup>
import StatusTag from '/@/components/StatusTag/index.vue'
const YES_OR_NO = [
{ label: '是', value: '1' },
{ label: '否', value: '0' }
]
</script>
```
### 纯文本模式(无边框和背景)
```vue
<StatusTag
:value="scope.row.tied"
:options="YES_OR_NO"
:show-tag="false"
/>
```
### 自定义类型映射
```vue
<StatusTag
:value="scope.row.status"
:options="statusOptions"
:type-map="{
'1': { type: 'success', effect: 'dark' },
'0': { type: 'danger', effect: 'light' }
}"
/>
```
### 自定义颜色映射(纯文本模式)
```vue
<StatusTag
:value="scope.row.status"
:options="statusOptions"
:show-tag="false"
:color-map="{
'1': '#67C23A',
'0': '#F56C6C'
}"
/>
```
### 完整示例
```vue
<template>
<el-table :data="tableData">
<el-table-column label="是否退休" width="100" align="center">
<template #default="scope">
<StatusTag
:value="scope.row.tied"
:options="YES_OR_NO"
/>
</template>
</el-table-column>
</el-table>
</template>
<script setup lang="ts">
import { defineAsyncComponent } from 'vue'
import global from '/@/components/tools/commondict.vue'
const StatusTag = defineAsyncComponent(() => import('/@/components/StatusTag/index.vue'))
const YES_OR_NO = global.YES_OR_NO
</script>
```
## 注意事项
1. **必须传入 `options`**:组件不提供默认选项,必须通过 `options` prop 传入选项列表
2. **值匹配**:组件会自动匹配字符串和数字类型的值(如 `'1'``1` 会被视为相同)
3. **样式优先级**:外部传入的 `typeMap``colorMap` 会覆盖默认样式
4. **未匹配值**:如果 `value``options` 中找不到对应项,会显示 `'-'`
## 样式说明
### 标签模式showTag: true
使用 Element Plus 的 `el-tag` 组件,支持所有 `el-tag` 的类型和效果:
- `type`: `success` | `info` | `warning` | `danger` | `primary`
- `effect`: `dark` | `light` | `plain`
### 纯文本模式showTag: false
使用纯文本显示,通过 CSS 颜色控制样式支持任何颜色值CSS 变量、十六进制、RGB 等)。

View File

@@ -0,0 +1,140 @@
<template>
<el-tag
v-if="showTag"
:type="tagType"
:effect="tagEffect"
>
{{ label }}
</el-tag>
<span v-else class="status-tag" :class="statusClass" :style="statusStyle">
{{ label }}
</span>
</template>
<script setup lang="ts">
import { computed } from 'vue'
interface Option {
label: string
value: string | number
}
interface Props {
value?: string | number // 当前值
options?: Option[] // 选项列表,格式:[{label: '是', value: '1'}, {label: '否', value: '0'}]
showTag?: boolean // 是否显示标签样式(有边框和背景),默认为 true
typeMap?: Record<string | number, { type: string; effect?: string }> // 自定义类型映射,如 {'1': {type: 'warning', effect: 'dark'}}
colorMap?: Record<string | number, string> // 纯文本模式下的颜色映射,如 {'1': '#E6A23C'}
}
const props = withDefaults(defineProps<Props>(), {
value: '',
options: () => [],
showTag: true,
typeMap: () => ({}),
colorMap: () => ({})
})
// 默认的类型映射(只使用字符串键)
const defaultTypeMap: Record<string, { type: string; effect: string }> = {
'1': { type: 'warning', effect: 'dark' },
'0': { type: 'primary', effect: 'light' }
}
// 默认的颜色映射(只使用字符串键)
const defaultColorMap: Record<string, string> = {
'1': 'var(--el-color-warning)',
'0': 'var(--el-color-primary)'
}
// 获取值的字符串形式(用于查找映射)
const getValueKey = (value: string | number): string => {
return String(value)
}
// 合并后的类型映射(外部传入优先,否则使用默认)
const mergedTypeMap = computed(() => {
// 将外部传入的 typeMap 也转换为字符串键
const externalTypeMap: Record<string, { type: string; effect?: string }> = {}
Object.keys(props.typeMap).forEach(key => {
externalTypeMap[String(key)] = props.typeMap[key]
})
return { ...defaultTypeMap, ...externalTypeMap }
})
// 合并后的颜色映射(外部传入优先,否则使用默认)
const mergedColorMap = computed(() => {
// 将外部传入的 colorMap 也转换为字符串键
const externalColorMap: Record<string, string> = {}
Object.keys(props.colorMap).forEach(key => {
externalColorMap[String(key)] = props.colorMap[key]
})
return { ...defaultColorMap, ...externalColorMap }
})
// 合并后的选项列表(必须通过外部传入 options
const mergedOptions = computed(() => {
// 必须传入 options否则返回空数组
return props.options && props.options.length > 0 ? props.options : []
})
// 根据值找到对应的选项
const currentOption = computed(() => {
return mergedOptions.value.find((opt: Option) => {
const optValue = String(opt.value)
const propValue = String(props.value)
return optValue === propValue || Number(opt.value) === Number(props.value)
})
})
// 显示标签
const label = computed(() => {
return currentOption.value?.label || '-'
})
// 标签类型showTag 为 true 时使用)
const tagType = computed(() => {
const valueKey = getValueKey(props.value)
if (mergedTypeMap.value[valueKey]) {
return mergedTypeMap.value[valueKey].type
}
return 'info'
})
// 标签效果showTag 为 true 时使用)
const tagEffect = computed(() => {
const valueKey = getValueKey(props.value)
if (mergedTypeMap.value[valueKey]?.effect) {
return mergedTypeMap.value[valueKey].effect
}
return 'light'
})
// 纯文本模式下的样式类
const statusClass = computed(() => {
if (props.colorMap[props.value]) {
return ''
}
return 'status-default'
})
// 纯文本模式下的内联样式
const statusStyle = computed(() => {
const valueKey = getValueKey(props.value)
if (mergedColorMap.value[valueKey]) {
return { color: mergedColorMap.value[valueKey] }
}
return {}
})
</script>
<style scoped>
.status-tag {
display: inline-block;
}
.status-default {
color: var(--el-text-color-regular);
}
</style>