This commit is contained in:
guochunsi
2026-01-16 18:35:58 +08:00
parent 61b3745807
commit ebc1366b07
10 changed files with 774 additions and 164 deletions

View File

@@ -0,0 +1,168 @@
<template>
<div class="icon-text" :style="containerStyle">
<el-icon
v-if="icon"
class="icon-text-icon"
:style="iconStyle">
<component :is="icon" />
</el-icon>
<span
v-if="text"
class="icon-text-text"
:style="textStyle">
{{ text }}
</span>
<slot />
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { Component } from 'vue'
// 尺寸配置映射(参考 el-tag 的尺寸)
const sizeConfig = {
small: {
iconSize: 14,
textSize: 12,
gap: 4
},
medium: {
iconSize: 16,
textSize: 14,
gap: 4
},
large: {
iconSize: 20,
textSize: 16,
gap: 5
}
}
// 类型颜色映射(与 el-tag 保持一致,提高可读性)
const typeColorMap: Record<string, string> = {
success: '#67c23a', // 成功 - 绿色
danger: '#f56c6c', // 危险 - 红色
warning: '#e6a23c', // 警告 - 橙色
info: '#909399', // 信息 - 灰色
primary: '#409eff' // 主要 - 蓝色
}
interface Props {
// 图标组件Element Plus 图标)
icon?: Component | string
// 文字内容
text?: string
// 类型(类似 el-tag 的 typesuccess、danger、warning、info、primary
type?: 'success' | 'danger' | 'warning' | 'info' | 'primary'
// 尺寸(类似 el-tag 的 sizesmall、medium、large
size?: 'small' | 'medium' | 'large'
// 图标颜色(优先级高于 type
iconColor?: string
// 文字颜色(优先级高于 type
textColor?: string
// 图标尺寸单位px优先级高于 size
iconSize?: number | string
// 文字尺寸单位px优先级高于 size
textSize?: number | string
// 图标和文字之间的间距单位px优先级高于 size
gap?: number | string
// 对齐方式
align?: 'left' | 'center' | 'right'
}
const props = withDefaults(defineProps<Props>(), {
icon: undefined,
text: '',
type: undefined,
size: 'medium',
iconColor: '',
textColor: '',
iconSize: undefined,
textSize: undefined,
gap: undefined,
align: 'left'
})
// 获取实际尺寸配置
const actualSizeConfig = computed(() => {
const config = sizeConfig[props.size]
return {
iconSize: props.iconSize ?? config.iconSize,
textSize: props.textSize ?? config.textSize,
gap: props.gap ?? config.gap
}
})
// 获取实际颜色
const actualIconColor = computed(() => {
if (props.iconColor) return props.iconColor
if (props.type && typeColorMap[props.type]) return typeColorMap[props.type]
return ''
})
const actualTextColor = computed(() => {
if (props.textColor) return props.textColor
if (props.type && typeColorMap[props.type]) return typeColorMap[props.type]
return ''
})
// 容器样式
const containerStyle = computed(() => {
const styles: Record<string, string> = {
display: 'inline-flex',
alignItems: 'center',
gap: `${actualSizeConfig.value.gap}px`
}
if (props.align === 'center') {
styles.justifyContent = 'center'
} else if (props.align === 'right') {
styles.justifyContent = 'flex-end'
}
return styles
})
// 图标样式
const iconStyle = computed(() => {
const styles: Record<string, string> = {
fontSize: `${actualSizeConfig.value.iconSize}px`,
verticalAlign: 'middle'
}
if (actualIconColor.value) {
styles.color = actualIconColor.value
}
return styles
})
// 文字样式
const textStyle = computed(() => {
const styles: Record<string, string> = {
fontSize: `${actualSizeConfig.value.textSize}px`,
verticalAlign: 'middle'
}
if (actualTextColor.value) {
styles.color = actualTextColor.value
}
return styles
})
</script>
<style scoped lang="scss">
.icon-text {
line-height: 1;
.icon-text-icon {
flex-shrink: 0;
}
.icon-text-text {
white-space: nowrap;
}
}
</style>

View File

@@ -16,6 +16,7 @@ import Sign from '/@/components/Sign/index.vue';
import ChinaArea from '/@/components/ChinaArea/index.vue';
import OrgSelector from '/@/components/OrgSelector/index.vue';
import AiEditor from '/@/components/AiEditor/index.vue';
import IconText from '/@/components/IconText/index.vue';
// 第三方组件
import ElementPlus from 'element-plus';
@@ -56,6 +57,7 @@ export default {
app.component('ChinaArea', ChinaArea);
app.component('OrgSelector', OrgSelector);
app.component('Sign', Sign);
app.component('IconText', IconText);
// 导入全部的elmenet-plus的图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {