Files
admin-sjzx/src/components/table/fieldRender/index.vue
2025-01-15 10:44:57 +08:00

252 lines
8.5 KiB
Vue

<template>
<!-- text -->
<div v-if="field.render == 'renderFormatter'">
{{ fieldValue }}
</div>
<!-- Icon -->
<Icon class="ba-icon-dark" v-if="field.render == 'icon'" :name="fieldValue ? fieldValue : field.default ?? ''" />
<!-- switch -->
<el-switch v-if="field.render == 'switch'" @change="onChangeField(field, $event)"
:model-value="fieldValue.toString()" :loading="row.loading" inline-prompt :active-value="field.activeValue"
:active-text="field.activeText" :inactive-value="field.inactiveValue" :inactive-text="field.inactiveText" />
<!-- image -->
<div v-if="field.render == 'image' && fieldValue" class="ba-render-image">
<el-image :hide-on-click-modal="true" :preview-teleported="true" :preview-src-list="[fullUrl(fieldValue)]"
:src="fieldValue.length > 100 ? fieldValue : fullUrl(fieldValue)"></el-image>
</div>
<!-- tag -->
<div v-if="field.render == 'tag' && fieldValue !== ''">
<el-tag :type="getTagType(fieldValue, field.custom) || 'primary'" :effect="field.effect ||'light'" size="small">
{{ field.replaceValue ? field.replaceValue[fieldValue] : fieldValue }}
</el-tag>
</div>
<!-- datetime -->
<div v-if="field.render == 'datetime'">
{{ !fieldValue ? '/' : timeFormat(fieldValue, field.timeFormat ?? undefined) }}
</div>
<!-- color -->
<div v-if="field.render == 'color'">
<div :style="{ background: fieldValue }" class="ba-render-color"></div>
</div>
<!-- customTemplate 自定义模板 -->
<div v-if="field.render == 'customTemplate'"
v-html="field.customTemplate ? field.customTemplate(row, field, fieldValue, column, index) : ''"></div>
<!-- 自定义组件/函数渲染 -->
<component v-if="field.render == 'customRender'" :is="field.customRender" :renderRow="row" :renderField="field"
:renderValue="fieldValue" :renderColumn="column" :renderIndex="index" />
<!-- 按钮组 -->
<div v-if="field.render == 'buttons' && buttons" class="cn-render-buttons">
<template v-for="(btn, idx) in buttons" :key="idx">
<!-- 常规按钮 -->
<el-button link v-if="btn.render == 'basicButton'" @click="onButtonClick(btn)" :class="btn.class"
class="table-operate" :type="btn.type" :disabled="btn.showDisabled && btn.showDisabled(row, field)"
:loading="props.row.loading || false" v-bind="btn.attr">
<div v-if="btn.text || btn.title" class="table-operate-text">{{ btn.text || btn.title }}</div>
</el-button>
<!-- 带提示信息的按钮 -->
<el-tooltip v-if="btn.render == 'tipButton'" :disabled="btn.title && !btn.disabledTip ? false : true"
:content="btn.title" placement="top">
<el-button link @click="onButtonClick(btn)" :class="btn.class" class="table-operate" :type="btn.type"
v-bind="btn.attr">
<div v-if="btn.text || btn.title" class="table-operate-text">
{{ btn.text || btn.title }}
</div>
</el-button>
</el-tooltip>
<!-- 带确认框的按钮 -->
<el-popconfirm v-if="btn.render == 'confirmButton'" :disabled="btn.disabled && btn.disabled(row, field)"
v-bind="btn.popconfirm" @confirm="onButtonClick(btn)">
<template #reference>
<div style="display: inline-block">
<el-button link :class="btn.class" class="table-operate" :type="btn.type" v-bind="btn.attr">
<div v-if="btn.text || btn.title" class="table-operate-text">
{{ btn.text || btn.title }}
</div>
</el-button>
</div>
</template>
</el-popconfirm>
<el-dropdown v-if="btn.render == 'dropdown'" trigger="click" @command="handlerCommand">
<el-button link type="primary" class="table-operate">
<div class="table-operate-text">更多</div>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="item in btn.buttons" :key="item.text" :command="item"
:disabled="item.showDisabled && item.showDisabled(row, field)" :style="{
color: item.type === 'primary' ? 'var(--el-color-primary)' : 'var(--el-color-danger)'
}">
{{ item.text }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</div>
</template>
<script setup lang="ts">
import { ref, inject } from 'vue'
import { ElMessageBox, type TagProps } from 'element-plus'
import type TableStoreClass from '@/utils/tableStore'
import { fullUrl, timeFormat } from '@/utils/common'
import type { VxeColumnProps } from 'vxe-table'
const TableStore = inject('tableStore') as TableStoreClass
interface Props {
row: TableRow
field: TableColumn
column: VxeColumnProps
index: number
}
const props = defineProps<Props>()
// 字段值(单元格值)
const fieldName = ref(props.field.field)
const fieldValue = ref(fieldName.value ? props.row[fieldName.value] : '')
if (fieldName.value && fieldName.value.indexOf('.') > -1) {
let fieldNameArr = fieldName.value.split('.')
let val: any = ref(props.row[fieldNameArr[0]])
for (let index = 1; index < fieldNameArr.length; index++) {
val.value = val.value ? val.value[fieldNameArr[index]] ?? '' : ''
}
fieldValue.value = val.value
}
if (props.field.renderFormatter && typeof props.field.renderFormatter == 'function') {
fieldValue.value = props.field.renderFormatter(props.row, props.field, fieldValue.value, props.column, props.index)
}
const onChangeField = (row: any, value: any) => {
row.onChangeField && row.onChangeField(props.row, value)
// TableStore.onTableAction('field-change', { value: value, ...props })
}
const onButtonClick = (btn: OptButton) => {
btn.click && btn.click(props.row, props.field)
}
const getTagType = (value: string, custom: any): TagProps['type'] => {
return custom && custom[value] ? custom[value] : ''
}
// 按钮组处理 最多显示三个按钮 多余的显示为下拉
const buttonsFilter = props.field.buttons?.filter(btn => !(btn.disabled && btn.disabled(props.row, props.field))) || []
const buttons = ref<any[]>([])
if (buttonsFilter.length > 3) {
buttonsFilter?.forEach((btn, index) => {
btn.text = btn.text || btn.title
if (index < 2) {
buttons.value.push(btn)
} else {
if (buttons.value.length > 2) {
buttons.value[buttons.value.length - 1].buttons.push(btn)
} else {
buttons.value.push({
render: 'dropdown',
buttons: [btn]
})
}
}
})
} else {
buttons.value = buttonsFilter
}
const handlerCommand = (item: OptButton) => {
switch (item.render) {
case 'basicButton':
onButtonClick(item)
break
case 'confirmButton':
ElMessageBox.confirm(item.popconfirm?.title || '提示', {
confirmButtonText: item.popconfirm?.confirmButtonText || '确认',
cancelButtonText: item.popconfirm?.cancelButtonText || '取消',
type: 'warning'
}).then(() => {
onButtonClick(item)
})
default:
break
}
}
</script>
<style scoped lang="scss">
.m-10 {
margin: 4px;
}
.ba-render-image {
text-align: center;
}
.images-item {
width: 50px;
margin: 0 5px;
}
.el-image {
height: 36px;
// width: 36px;
}
.table-operate-text {
padding-left: 5px;
font-size: 12px;
}
.table-operate {
padding: 4px 5px;
height: auto;
}
.cn-render-buttons {
display: flex;
align-items: center;
justify-content: center;
.icon {
font-size: 12px !important;
// color: var(--ba-bg-color-overlay) !important;
}
}
.move-button {
cursor: move;
}
.ml-6 {
display: inline-flex;
vertical-align: middle;
margin-left: 6px;
}
.ml-6+.el-button {
margin-left: 6px;
}
.ba-render-color {
height: 25px;
width: 100%;
}
.cn-render-buttons {
:deep(.el-button) {
margin-left: 0;
}
}
</style>