<script lang="ts" setup>
|
import type { TrendTableColumn, TrendTableOption } from '../helpers/trendOptionPopup';
|
|
import { computed, ref } from 'vue';
|
|
import { ChevronDown, Search } from '@vben/icons';
|
|
import { Modal as AModal } from 'ant-design-vue';
|
|
import { filterTrendTableOptions, getTrendOptionSummary, normalizeTrendOptionValue } from '../helpers/trendOptionPopup';
|
|
defineOptions({ name: 'SxtTrendTablePopup' });
|
|
const props = withDefaults(
|
defineProps<{
|
columns: TrendTableColumn[];
|
disabled?: boolean;
|
options: TrendTableOption[];
|
placeholder?: string;
|
popupTitle: string;
|
value?: string[];
|
width?: number;
|
}>(),
|
{
|
disabled: false,
|
placeholder: '请选择',
|
value: () => [],
|
width: 900,
|
},
|
);
|
|
const emit = defineEmits<{
|
change: [value: string[]];
|
'update:value': [value: string[]];
|
}>();
|
|
const open = ref(false);
|
const keyword = ref('');
|
const draftKeys = ref<string[]>([]);
|
|
const displayText = computed(() => getTrendOptionSummary(props.value, props.options));
|
const searchableColumnKeys = computed(() => props.columns.map((column) => column.dataIndex));
|
const filteredOptions = computed(() => filterTrendTableOptions(props.options, keyword.value, searchableColumnKeys.value));
|
const pagination = computed(() => ({
|
pageSize: 25,
|
pageSizeOptions: ['10', '25', '50', '100'],
|
showSizeChanger: true,
|
showTotal: (total: number) => `共 ${total} 条`,
|
}));
|
const rowSelection = computed(() => ({
|
onChange: (keys: Array<number | string>) => {
|
draftKeys.value = keys.map(String);
|
},
|
preserveSelectedRowKeys: true,
|
selectedRowKeys: draftKeys.value,
|
}));
|
|
function toggleRowSelection(value: string) {
|
draftKeys.value = draftKeys.value.includes(value) ? draftKeys.value.filter((key) => key !== value) : [...draftKeys.value, value];
|
}
|
|
function customRow(record: TrendTableOption) {
|
return {
|
onClick: (event: MouseEvent) => {
|
const target = event.target as Element | null;
|
if (target?.closest('.ant-checkbox-wrapper, input, button, a')) return;
|
toggleRowSelection(record.value);
|
},
|
};
|
}
|
|
function openPopup() {
|
if (props.disabled) return;
|
keyword.value = '';
|
draftKeys.value = normalizeTrendOptionValue(props.value);
|
open.value = true;
|
}
|
|
function closePopup() {
|
open.value = false;
|
}
|
|
function emitValue(value: string[]) {
|
emit('update:value', value);
|
emit('change', value);
|
}
|
|
function confirmSelection() {
|
emitValue([...draftKeys.value]);
|
closePopup();
|
}
|
</script>
|
|
<template>
|
<div class="trend-table-popup">
|
<a-input :disabled="disabled" :placeholder="placeholder" :title="displayText" :value="displayText" class="popup-trigger" readonly @click="openPopup">
|
<template #suffix>
|
<ChevronDown :size="16" class="dropdown-icon" />
|
</template>
|
</a-input>
|
|
<AModal
|
v-model:open="open"
|
:body-style="{ padding: '16px' }"
|
:destroy-on-close="true"
|
:mask-closable="false"
|
:title="popupTitle"
|
:width="width"
|
@cancel="closePopup"
|
@ok="confirmSelection">
|
<div class="table-toolbar">
|
<a-input v-model:value="keyword" allow-clear placeholder="请输入名称或编码搜索">
|
<template #prefix><Search :size="16" /></template>
|
</a-input>
|
</div>
|
|
<a-table
|
class="fixed-height-table"
|
:columns="columns"
|
:custom-row="customRow"
|
:data-source="filteredOptions"
|
:pagination="pagination"
|
row-key="value"
|
:row-selection="rowSelection"
|
:scroll="{ x: 'max-content', y: 420 }"
|
size="middle" />
|
</AModal>
|
</div>
|
</template>
|
|
<style lang="scss" scoped>
|
.trend-table-popup,
|
.popup-trigger {
|
width: 100%;
|
}
|
|
.popup-trigger {
|
cursor: pointer;
|
|
:deep(input) {
|
overflow: hidden;
|
text-overflow: ellipsis;
|
cursor: pointer;
|
}
|
}
|
|
.dropdown-icon {
|
color: rgb(0 0 0 / 45%);
|
pointer-events: none;
|
}
|
|
.table-toolbar {
|
margin-bottom: 12px;
|
}
|
|
.fixed-height-table {
|
:deep(.ant-table-tbody > tr) {
|
cursor: pointer;
|
}
|
|
:deep(.ant-table-body) {
|
height: calc(min(440px, 55vh) - 104px);
|
overflow-y: auto !important;
|
}
|
}
|
</style>
|