ParamsTable.vue 4.81 KB
<script setup lang="ts" >
import { getUUID } from '@/utils';
import { ButtonProps, DataTableColumns, InputProps, NButton, NDataTable, NIcon, NInput, NSpace, NTag, NTooltip, TagProps } from 'naive-ui';
import { computed, h, ref, unref, watch } from 'vue';
import { Subtract, Add } from '@vicons/carbon'
import { isObject } from '@/utils/external/is';

interface DataSource {
  id: string
  value?: string
  keyName?: string
  result?: boolean
}

const columns: DataTableColumns<DataSource> = [
  {
    title: '序号',
    key: 'index',
    render: (_, index) => index + 1,
    width: 50,
  },
  {
    title: 'Key',
    key: 'keyName',
    render: (row, index) => {
      return h(
        NInput,
        {
          value: row.keyName,
          onBlur: () => handleInputBlur(row),
          onUpdateValue: (value: string) => unref(dataSource)[index].keyName = value,
          size: 'small',
          disabled: props.disabled
        } as InputProps
      )
    }
  },
  {
    title: 'Value',
    key: 'value',
    render: (row, index) => {
      return h(
        NInput,
        {
          value: row.value,
          onBlur: () => handleInputBlur(row),
          onUpdateValue: (value: string) => unref(dataSource)[index].value = value,
          size: 'small',
          disabled: props.disabled
        } as InputProps
      )
    }
  },
  {
    title: '操作',
    key: 'actions',
    render: (row) => {
      return h(
        NSpace,
        () => [
          h(
            NTooltip,
            null,
            {
              trigger: () => h(
                NButton,
                {
                  type: 'success',
                  size: 'small',
                  ghost: true,
                  onClick: () => handleAddRow(row),
                  disabled: props.disabled || !unref(canAddRow)
                } as ButtonProps,
                {
                  default: () => h(NIcon, () => h(Add))
                }
              ),
              default: () => '插入行'
            }
          ),
          h(
            NTooltip,
            null,
            {
              trigger: () => h(
                NButton,
                {
                  type: 'warning',
                  size: 'small',
                  ghost: true,
                  onClick: () => handleSubtractRow(row),
                  // disabled: props.disabled || !unref(canDeleteRow)
                } as ButtonProps,
                {
                  default: () => h(NIcon, () => h(Subtract))
                }
              ),
              default: () => '删除行'
            }
          )
        ]
      )
    },
    width: 100,
  },
  {
    title: '结果',
    key: 'result',
    render: (row) => {
      return h(NTag, { type: row.result ? 'success' : 'error' } as TagProps, () => `${row.result ? '' : '未'}通过`)
    },
    width: 80
  }
]

const props = withDefaults(
  defineProps<{
    value?: Recordable
    disabled?: boolean
    maxRow?: number
  }>(),
  {
    disabled: false,
    maxRow: 50,
  }
)


const emit = defineEmits(['update:value'])

const createNewRow = () => {
  return { id: getUUID(), result: true } as DataSource
}

const dataSource = ref<DataSource[]>([
  createNewRow()
])

watch(
  () => props.value,
  (target) => {
    if (target && isObject(target) && Object.keys(target).length) {
      dataSource.value = Object.keys(props.value || {}).map(keyName => ({ ...createNewRow(), keyName, value: Reflect.get(props.value || {}, keyName) }))
    } else {
      dataSource.value = [createNewRow()]
    } 
  },
  {
    immediate: true,
    deep: true
  }
)

const canDeleteRow = computed(() => {
  return unref(dataSource).length >= 2
})

const canAddRow = computed(() => {
  return unref(dataSource).length < props.maxRow
})

const handleAddRow = (record: DataSource) => {
  const index = unref(dataSource).findIndex(item => item.id === record.id)
  unref(dataSource).splice(index + 1, 0, createNewRow())
}

const handleSubtractRow = (record: DataSource) => {
  const index = unref(dataSource).findIndex(item => item.id === record.id)
  if (unref(dataSource).length === 1) {
    emit('update:value', {})
  } else {
    unref(dataSource).splice(index, 1)
    emit('update:value', getHeaderConfiguration())
  }
}


const handleInputBlur = (record: DataSource) => {
  const { keyName, value } = record
  record.result = !!(keyName && value)
  if (unref(dataSource).every(item => item.result)) {
    emit('update:value', getHeaderConfiguration())
  }
}

const getHeaderConfiguration = () => {
  return unref(dataSource).reduce((prev, next) => {
    const { result, value, keyName } = next
    const header = result && value && keyName ? { [keyName]: value } : {}
    return { ...prev, ...header }
  }, {} as Recordable)
}

</script>

<template>
  <NDataTable size="small" :columns="columns" :row-key="rowData => rowData.id" :data="dataSource" max-height="300" />
</template>