161 lines
5.6 KiB
Vue
161 lines
5.6 KiB
Vue
<template>
|
|
<div>
|
|
<UTable :data="tableData" :columns="tableColumns" class="w-full" :ui="{ td: 'p-2' }">
|
|
<template v-for="col in dataColumns" :key="col.key" #[`${col.key}-cell`]="slotProps">
|
|
<!-- Column with cross-reference -->
|
|
<USelectMenu
|
|
v-if="hasColumnReference(col.colIndex)"
|
|
:model-value="getCellValueForSelect(slotProps.row as TableRow<TableRowData>, col.key, col.colIndex)"
|
|
:items="getColumnOptions(col.colIndex, (slotProps.row as TableRow<TableRowData>).original)"
|
|
:disabled="disabled"
|
|
:placeholder="$t('applicationForms.formElements.table.selectValue')"
|
|
:multiple="isColumnMultipleAllowed(col.colIndex)"
|
|
class="w-full min-w-32"
|
|
@update:model-value="
|
|
(val: string | string[]) =>
|
|
$emit('update:cellValue', (slotProps.row as TableRow<TableRowData>).index, col.key, col.colIndex, val)
|
|
"
|
|
/>
|
|
<!-- Read-only column -->
|
|
<span v-else-if="isColumnReadOnly(col.colIndex)" class="text-muted px-2 py-1">
|
|
{{ formatCellDisplay(slotProps.row as any, col.key, col.colIndex) }}
|
|
</span>
|
|
<!-- Checkbox column -->
|
|
<div v-else-if="isColumnCheckbox(col.colIndex)" class="flex justify-center">
|
|
<UCheckbox
|
|
:model-value="getCellValueForCheckbox(slotProps.row as TableRow<TableRowData>, col.key)"
|
|
:disabled="disabled"
|
|
@update:model-value="
|
|
(val: boolean | 'indeterminate') =>
|
|
$emit(
|
|
'update:checkboxCell',
|
|
(slotProps.row as TableRow<TableRowData>).index,
|
|
col.colIndex,
|
|
val === true
|
|
)
|
|
"
|
|
/>
|
|
</div>
|
|
<!-- Regular text input with auto-resizing textarea -->
|
|
<UTextarea
|
|
v-else
|
|
:model-value="getCellValue(slotProps.row as TableRow<TableRowData>, col.key)"
|
|
:disabled="disabled"
|
|
:rows="1"
|
|
autoresize
|
|
:maxrows="0"
|
|
class="w-full min-w-32"
|
|
@update:model-value="
|
|
(val: string | number) =>
|
|
$emit('update:cell', (slotProps.row as TableRow<TableRowData>).index, col.key, String(val))
|
|
"
|
|
/>
|
|
</template>
|
|
<template v-if="canModifyRows" #actions-cell="{ row }">
|
|
<UButton
|
|
v-if="!disabled"
|
|
icon="i-lucide-trash-2"
|
|
color="error"
|
|
variant="ghost"
|
|
size="xs"
|
|
:aria-label="$t('applicationForms.formElements.table.removeRow')"
|
|
@click="$emit('removeRow', row.index)"
|
|
/>
|
|
</template>
|
|
</UTable>
|
|
|
|
<div v-if="tableData.length === 0" class="text-center text-dimmed py-4">
|
|
{{ $t('applicationForms.formElements.table.noData') }}
|
|
</div>
|
|
|
|
<UButton
|
|
v-if="!disabled && canModifyRows"
|
|
variant="outline"
|
|
size="sm"
|
|
leading-icon="i-lucide-plus"
|
|
:class="addRowButtonClass"
|
|
@click="$emit('addRow')"
|
|
>
|
|
{{ $t('applicationForms.formElements.table.addRow') }}
|
|
</UButton>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type { FormOptionDto } from '~~/.api-client'
|
|
import type { TableColumn, TableRow } from '@nuxt/ui'
|
|
|
|
type CellValue = string | string[] | boolean
|
|
type TableRowData = Record<string, CellValue>
|
|
|
|
interface DataColumn {
|
|
key: string
|
|
colIndex: number
|
|
}
|
|
|
|
const props = defineProps<{
|
|
tableData: TableRowData[]
|
|
tableColumns: TableColumn<TableRowData>[]
|
|
dataColumns: DataColumn[]
|
|
formOptions: FormOptionDto[]
|
|
disabled?: boolean
|
|
canModifyRows: boolean
|
|
addRowButtonClass?: string
|
|
getColumnOptions: (colIndex: number, currentRowData?: TableRowData) => string[]
|
|
}>()
|
|
|
|
defineEmits<{
|
|
(e: 'update:cell', rowIndex: number, columnKey: string, value: string): void
|
|
(e: 'update:cellValue', rowIndex: number, columnKey: string, colIndex: number, value: string | string[]): void
|
|
(e: 'update:checkboxCell', rowIndex: number, colIndex: number, value: boolean): void
|
|
(e: 'addRow'): void
|
|
(e: 'removeRow', rowIndex: number): void
|
|
}>()
|
|
|
|
function hasColumnReference(colIndex: number): boolean {
|
|
const option = props.formOptions[colIndex]
|
|
return !!option?.columnConfig?.sourceTableReference && !isColumnReadOnly(colIndex)
|
|
}
|
|
|
|
function isColumnReadOnly(colIndex: number): boolean {
|
|
const option = props.formOptions[colIndex]
|
|
return option?.columnConfig?.isReadOnly === true
|
|
}
|
|
|
|
function isColumnMultipleAllowed(colIndex: number): boolean {
|
|
const option = props.formOptions[colIndex]
|
|
return option?.columnConfig?.isMultipleAllowed === true
|
|
}
|
|
|
|
function isColumnCheckbox(colIndex: number): boolean {
|
|
const option = props.formOptions[colIndex]
|
|
return option?.columnConfig?.isCheckbox === true
|
|
}
|
|
|
|
function getCellValue(row: TableRow<TableRowData>, columnKey: string): string {
|
|
const value = row.original[columnKey]
|
|
return typeof value === 'string' ? value : ''
|
|
}
|
|
|
|
function getCellValueForSelect(row: TableRow<TableRowData>, columnKey: string, colIndex: number): string | string[] {
|
|
const value = row.original[columnKey]
|
|
if (isColumnMultipleAllowed(colIndex)) {
|
|
return Array.isArray(value) ? value : []
|
|
}
|
|
return typeof value === 'string' ? value : ''
|
|
}
|
|
|
|
function getCellValueForCheckbox(row: TableRow<TableRowData>, columnKey: string): boolean {
|
|
const value = row.original[columnKey]
|
|
return value === true
|
|
}
|
|
|
|
function formatCellDisplay(row: TableRow<TableRowData>, columnKey: string, colIndex: number): string {
|
|
const value = row.original[columnKey]
|
|
if (isColumnMultipleAllowed(colIndex) && Array.isArray(value)) {
|
|
return value.length > 0 ? value.join(', ') : '-'
|
|
}
|
|
return (typeof value === 'string' ? value : '') || '-'
|
|
}
|
|
</script>
|