2025-08-28 17:29:25 +08:00

185 lines
3.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- components/uni-app-tag/uni-app-tag.vue -->
<template>
<view class="uni-app-tag-container">
<!-- 匹配的标签 -->
<template
v-for="(item, index) in matchedItems"
:key="getValue(item)"
>
<!-- 普通 spandefault 类型 + class -->
<span
v-if="isDefaultTag(item)"
class="uni-app-tag-span"
:class="item.elTagClass"
>
{{ getText(item) }}&nbsp;
</span>
<!-- 自定义样式 view 模拟 tag -->
<view
v-else
class="uni-app-tag"
:class="[
`uni-app-tag--${getUniType(item.elTagType)}`,
item.elTagClass
]"
>
{{ getText(item) }}
</view>
</template>
<!-- 未匹配的值 -->
<text v-if="unmatch && showValue" class="uni-app-tag-unmatch">
{{ unmatchText }}
</text>
</view>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
/* 选项数组 */
options: {
type: Array,
default: () => []
},
/* 当前值String | Number | Array */
value: [String, Number, Array],
/* 是否显示未匹配值 */
showValue: {
type: Boolean,
default: true
},
/* 字符串分隔符(仅 value 为字符串时生效) */
separator: {
type: String,
default: ','
},
/* 字段映射:值字段名 */
valueField: {
type: String,
default: 'dictValue'
},
/* 字段映射:文本字段名 */
textField: {
type: String,
default: 'dictLabel'
}
})
/* 工具函数:统一取出值 / 文本 */
const getValue = (opt) => String(opt[props.valueField])
const getText = (opt) => opt[props.textField] ?? ''
/* 1. 统一转成字符串数组 */
const values = computed(() => {
if (props.value == null || props.value === '') return []
return Array.isArray(props.value)
? props.value.map(String)
: String(props.value).split(props.separator).map(v => v.trim())
})
/* 2. 匹配到的选项 */
const matchedItems = computed(() =>
values.value
.map(val => props.options.find(opt => getValue(opt) === val))
.filter(Boolean)
)
/* 3. 未匹配的值 */
const unmatchArray = computed(() => {
if (!values.value.length || !props.options.length) return []
return values.value.filter(
val => !props.options.some(opt => getValue(opt) === val)
)
})
const unmatch = computed(() => unmatchArray.value.length > 0)
const unmatchText = computed(() => unmatchArray.value.join(' '))
/* 4. 判断是否为默认 tagdefault 且无自定义 class */
const isDefaultTag = (item) => {
const type = item.elTagType || 'default'
const cls = item.elTagClass || ''
return (type === 'default' || !type) && !cls
}
/* 5. el-tag type -> uni 类名映射 */
const getUniType = (type) => {
const map = {
primary: 'primary',
success: 'success',
warning: 'warning',
danger: 'error',
info: 'info',
default: 'default'
}
return map[type] || 'default'
}
</script>
<style scoped>
.uni-app-tag-container {
display: flex;
flex-wrap: wrap;
align-items: center;
font-size: 14px;
}
.uni-app-tag-span {
margin-right: 8px;
white-space: nowrap;
}
.uni-app-tag {
display: inline-flex;
align-items: center;
padding: 2px 8px;
border-radius: 4px;
font-size: 12px;
margin-right: 8px;
white-space: nowrap;
}
.uni-app-tag--primary {
background-color: #d0e3ff;
color: #0066ff;
border: 1px solid #99ccff;
}
.uni-app-tag--success {
background-color: #dcf5e7;
color: #00aa55;
border: 1px solid #88ccaa;
}
.uni-app-tag--warning {
background-color: #fff0d9;
color: #cc8800;
border: 1px solid #ffcc88;
}
.uni-app-tag--error {
background-color: #ffd9dc;
color: #ff3344;
border: 1px solid #ff99aa;
}
.uni-app-tag--info {
background-color: #e6e6e6;
color: #666666;
border: 1px solid #cccccc;
}
.uni-app-tag--default {
background-color: #f4f4f4;
color: #333;
border: 1px solid #ddd;
}
.uni-app-tag-unmatch {
margin-left: 4px;
color: #999;
font-size: 12px;
}
</style>