81c5a74b创建于 2023年12月13日历史提交
<template>
  <div class="table-container">
    <Toolbar
      :status="barStatus"
      @addLine="handleAddLine(data)"
      @removeLine="handleRemoveLine(data)"
    />
    <EditTable
      :data="props.data"
      :columns="tableColumns"
      :idKey="idKey"
      :rowStatusKey="rowStatusKey"
      :editingSuffix="editingSuffix"
      :editedSuffix="editedSuffix"
      :menuList="['advancedCopy']"
      v-model:globalEditing="globalEditing"
      @selectionChange="handleSelectionChange"
    >
      <template v-for="item in tableColumns" :key="item.prop" v-slot:[item.prop]="scope">
        <el-input
          v-if="globalEditing && scope.row[item.prop + editingSuffix] && item.element == 'input'"
          v-model="scope.row[item.prop]"
          v-bind="item.attributes"
          @change="handleChangeValue(scope.row, scope.column)"
        />
        <el-input-number
          v-else-if="
            globalEditing && scope.row[item.prop + editingSuffix] && item.element == 'inputNumber'
          "
          v-model="scope.row[item.prop]"
          v-bind="item.attributes"
          :controls="false"
          @change="handleChangeValue(scope.row, scope.column)"
          style="width: 100%"
        />
        <el-select
          v-else-if="
            globalEditing && scope.row[item.prop + editingSuffix] && item.prop == 'dataType'
          "
          v-model="scope.row[item.prop]"
          v-bind="item.attributes"
          @change="handleChangeValue(scope.row, scope.column)"
        >
          <el-option
            v-for="op in dataTypeList"
            :key="op.value"
            :label="op.label"
            :value="op.value"
          />
        </el-select>
        <el-select
          v-else-if="
            globalEditing && scope.row[item.prop + editingSuffix] && item.prop == 'columnName'
          "
          v-model="scope.row[item.prop]"
          v-bind="item.attributes"
          @change="handleChangeValue(scope.row, scope.column)"
        >
          <el-option
            v-for="op in props.columns"
            :key="op.value"
            :label="op.label"
            :value="op.value"
          />
        </el-select>
        <el-cascader
          v-else-if="
            globalEditing && scope.row[item.prop + editingSuffix] && item.element == 'cascader'
          "
          v-model="scope.row[item.prop]"
          :props="cascaderProps"
          :options="item.options"
          @change="handleChangeValue(scope.row, scope.column)"
        />
        <el-checkbox
          v-else-if="item.element == 'checkbox'"
          v-model="scope.row[item.prop]"
          @change="handleChangeValue(scope.row, scope.column)"
        />
        <span v-else>{{ formatTextCell(scope.row[item.prop], item.element) }}</span>
      </template>
    </EditTable>
  </div>
</template>

<script lang="ts" setup>
  import type { CascaderProps } from 'element-plus';
  import EditTable from './EditTable2.vue';
  import Toolbar from './Toolbar.vue';
  import { getSchemaList, getSchemaObjectList } from '@/api/metaData';
  import { getTableColumn } from '@/api/table';
  import { useEditTabHooks } from './useEditTabHooks';
  import type { CommonParams, TableColumn, AvailColumnList } from '../types';
  interface FetchNode {
    name: string;
    oid: string;
  }
  const props = withDefaults(
    defineProps<{
      data: any[];
      commonParams: CommonParams;
      columns: AvailColumnList[];
    }>(),
    {
      data: () => [],
      columns: () => [],
    },
  );

  const emit = defineEmits<{
    (e: 'update:data', value: any[]): void;
  }>();

  const idKey = ref('_id');
  const rowStatusKey = ref('_rowStatus');
  const editingSuffix = ref('_isEditing');
  const editedSuffix = ref('_edited');
  const globalEditing = ref(false);
  const barStatus = reactive({
    addLine: true,
    removeLine: true,
  });

  const dataTypeList = ref([]);
  const data = computed({
    get: () => props.data,
    set: (val) => emit('update:data', val),
  });
  const tableColumns = ref<TableColumn[]>([
    {
      label: 'table.constraint.constrainName',
      prop: 'constrainName',
      slot: true,
      isI18nLabel: true,
      element: 'input',
    },
    {
      label: 'table.constraint.columnName',
      prop: 'columnName',
      slot: true,
      isI18nLabel: true,
      element: 'select',
      attributes: {
        multiple: true,
        collapseTags: true,
      },
      options: [],
    },
    {
      label: 'table.constraint.constrainType',
      prop: 'constrainType',
      slot: true,
      isI18nLabel: true,
      element: 'cascader',
      options: [
        {
          value: 'c',
          label: 'CHECK',
          disabled: false,
          leaf: true,
        },
        {
          value: 'u',
          label: 'UNIQUE',
          disabled: false,
          leaf: true,
        },
        {
          value: 'p',
          label: 'PRIMARY KEY',
          disabled: false,
          leaf: true,
        },
        {
          value: 's',
          label: 'PARTIAL CLUSTER KEY',
          disabled: false,
          leaf: true,
        },
        {
          value: 'f',
          label: 'FOREIGN KEY',
          disabled: false,
          leaf: false,
        },
      ],
    },
    {
      label: 'table.constraint.expression',
      prop: 'expression',
      slot: true,
      isI18nLabel: true,
      element: 'input',
    },
    {
      label: 'table.constraint.isDeffered',
      prop: 'isDeffered',
      slot: true,
      isI18nLabel: true,
      element: 'checkbox',
    },
    {
      label: 'common.description',
      prop: 'description',
      slot: true,
      isI18nLabel: true,
      element: 'input',
      attributes: {
        maxlength: 5000,
      },
    },
  ]);
  const cascaderProps: CascaderProps = {
    lazy: true,
    lazyLoad: async (node, resolve) => {
      if (node.level == 1) {
        resolve(await fetchSchemaList());
      } else if (node.level == 2) {
        resolve(await fetchSchemaContentList(node.value));
      } else if (node.level == 3) {
        resolve(await fetchColumnList(node));
      } else {
        resolve([]);
      }
    },
  };
  const formatTextCell = (value: string[] | string, type) => {
    if (type == 'cascader' && Array.isArray(value)) {
      enum ConstrainType {
        c = 'CHECK',
        u = 'UNIQUE',
        p = 'PRIMARY KEY',
        s = 'PRIMARY KEY',
        f = 'FOREIGN KEY',
      }
      return value.length > 1
        ? `${ConstrainType[value[0]]}/${value[1]}.${value[2]}.${value[3]}`
        : ConstrainType[value[0]];
    }
    if (['select'].includes(type) && Array.isArray(value)) return value.join(',');
    return value;
  };
  const fetchSchemaList = async () => {
    const data = (await getSchemaList({
      uuid: props.commonParams.uuid,
    })) as unknown as FetchNode[];
    return data.map((item) => ({ oid: item.oid, value: item.name, label: item.name, leaf: false }));
  };
  const fetchSchemaContentList = async (schema) => {
    const data = (await getSchemaObjectList({
      schema,
      uuid: props.commonParams.uuid,
    })) as unknown as any[];
    return data[0]?.table.map((item: FetchNode) => ({
      oid: item.oid,
      value: item.name,
      label: item.name,
      leaf: false,
    }));
  };
  const fetchColumnList = async (node) => {
    const res = (await getTableColumn({
      ...props.commonParams,
      schema: node.pathValues[1],
      oid: node.data.oid,
      tableName: node.data.value,
    })) as unknown as any;
    return res.result.map((item) => ({ value: item[0], label: item[0], leaf: true }));
  };
  const { handleChangeValue, handleSelectionChange, handleAddLine, handleRemoveLine } =
    useEditTabHooks({
      idKey: idKey.value,
      rowStatusKey: rowStatusKey.value,
      editingSuffix: editingSuffix.value,
      editedSuffix: editedSuffix.value,
    });
</script>

<style lang="scss" scoped>
  .table-container {
    flex: 1;
    display: flex;
    flex-direction: column;
  }
</style>