张诺
3 天以前 c7afec3ad75b22bc8b96d8129956913c2b473d9b
src/components/Table/EtableModify.vue
@@ -1,36 +1,92 @@
<template>
  <el-table v-loading="loading" :data="tableData" :border="border" :show-selection="showSelection" :height="height" :max-height="maxHeight"
    :header-cell-style="{ background: '#EBEEF5', color: '#3D3D3D' }" @selection-change="handleSelectionChange"
    @row-click="handleRowClick" @row-dblclick="handleRowDblClick" :row-class-name="tableRowClassName" @cell-click="handleCellClick" :max-width="maxWidth"
    @export="handleExport">
    <el-table-column v-if="showSelection" type="selection" width="55" align="center" />
    <el-table-column v-if="showIndex" label="序号" type="index" width="60" align="center" /> <template
      v-for="col in columns" :key="col.prop">
      <el-table-column v-bind="col" :show-overflow-tooltip="shouldShowTooltip(col, tableData)" align="center"> <template
          #default="scope">
  <el-table
    v-loading="loading"
    :data="tableData"
    :border="border"
    :show-selection="showSelection"
    :height="height"
    :max-height="maxHeight"
    :header-cell-style="{ background: '#EBEEF5', color: '#3D3D3D' }"
    @selection-change="handleSelectionChange"
    @row-click="handleRowClick"
    @row-dblclick="handleRowDblClick"
    :row-class-name="tableRowClassName"
    @cell-click="handleCellClick"
    :max-width="maxWidth"
    @export="handleExport"
    :show-overflow-tooltip="showOverflowTooltip"
  >
    <el-table-column
      v-if="showSelection"
      type="selection"
      width="55"
      align="center"
    />
    <el-table-column
      v-if="showIndex"
      label="序号"
      type="index"
      width="60"
      align="center"
    />
    <template v-for="col in columns" :key="col.prop">
      <el-table-column
        v-bind="col"
        :show-overflow-tooltip="false"
        align="center"
      >
        <template #default="scope">
          <template v-if="col.slot">
            <slot></slot>
          </template>
          <template v-else>
            <div class="cell-edit" @dblclick="handleCellEdit(scope.row, col.prop)"
              :class="{'editable': isColumnEditable(col.prop)}"> <span
                v-if="!scope.row.editing || !scope.row.editing[col.prop]" class="cell-text">
                {{ scope.row[col.prop] == null || scope.row[col.prop] === '' ? '--' : scope.row[col.prop] }}
            <div
              class="cell-edit"
              @dblclick="handleCellEdit(scope.row, col.prop)"
              :class="{ editable: isColumnEditable(col.prop) }"
            >
              <span
                v-if="!scope.row.editing || !scope.row.editing[col.prop]"
                class="cell-text"
              >
                {{
                  scope.row[col.prop] == null || scope.row[col.prop] === ""
                    ? "--"
                    : scope.row[col.prop]
                }}
              </span>
              <el-input v-else v-model="scope.row[col.prop]" size="small"
                @focus="handleCellFocus(scope.row, col.prop, $event)" @blur="handleCellSave(scope.row, col.prop)"
                @keyup.enter="handleCellSave(scope.row, col.prop)" class="cell-input" />
              <el-input
                v-else
                v-model="scope.row[col.prop]"
                size="small"
                @focus="handleCellFocus(scope.row, col.prop, $event)"
                @blur="handleCellSave(scope.row, col.prop)"
                @keyup.enter="handleCellSave(scope.row, col.prop)"
                class="cell-input"
              />
            </div>
          </template>
        </template>
      </el-table-column>
    </template>
    <!-- 操作列 -->
    <el-table-column v-if="showOperations" :label="operationsLabel" :width="operationsWidth" fixed="right" align="center">
    <el-table-column
      v-if="showOperations"
      :label="operationsLabel"
      :width="operationsWidth"
      fixed="right"
      align="center"
    >
      <template #default="scope">
        <slot name="operations" :row="scope.row">
          <el-button v-if="operations.includes('edit')" link type="primary" size="small"
            @click="handleEdit(scope.row)">编辑</el-button>
          <el-button
            v-if="operations.includes('edit')"
            link
            type="primary"
            size="small"
            @click="handleEdit(scope.row)"
            >编辑</el-button
          >
          <!--            <el-button-->
          <!--              v-if="operations.includes('delete')"-->
          <!--              link-->
@@ -43,119 +99,123 @@
    </el-table-column>
  </el-table>
</template>
  <script setup>
import { defineEmits, nextTick } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
<script setup>
import { defineEmits, nextTick } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
const props = defineProps({
  // 获取行样式
  tableRowClassName: {
    type: Function,
    default: () => ''
    default: () => "",
  },
  // 获取高度
  height: {
    type: [String, Number],
    default: 'auto'
    default: "auto",
  },
  // 是否允许编辑单元格
  editableCells: {
    type: Boolean,
    default: true
    default: true,
  },
  // 指定可编辑的列,如果为空数组则表示所有列都不可编辑
  editableColumns: {
    type: Array,
    default: () => []
    default: () => [],
  },
  // 最大宽度
  maxWidth: {
    type: [String, Number],
    default: 'auto'
    default: "auto",
  },
  handleCellClick: {
    type: Function,
    default: () => { }
    default: () => {},
  },
  handleRowClick: {
    type: Function,
    default: () => { }
    default: () => {},
  },
  handleExport: {
    type: Function,
    default: () => { }
    default: () => {},
  },
  handleRowDblClick: {
    type: Function,
    default: () => { }
    default: () => {},
  },
  // 高度
  maxHeight: {
    type: [String, Number],
    default: 'auto'
    default: "auto",
  },
  // 加载状态
  loading: {
    type: Boolean,
    default: false
    default: false,
  },
  //   border
  border: {
    type: Boolean,
    default: false
    default: false,
  },
  // 表格数据
  tableData: {
    type: Array,
    default: () => []
    default: () => [],
  },
  // 是否显示选择列
  showSelection: {
    type: Boolean,
    default: false
    default: false,
  },
  // 是否显示序号列
  showIndex: {
    type: Boolean,
    default: true
    default: true,
  },
  // 列配置
  columns: {
    type: Array,
    default: () => []
    default: () => [],
  },
  // 是否显示操作列
  showOperations: {
    type: Boolean,
    default: true
    default: true,
  },
  // 操作列标签
  operationsLabel: {
    type: String,
    default: '操作'
    default: "操作",
  },
  // 操作列宽度
  operationsWidth: {
    type: [String, Number],
    default: 100
    default: 100,
  },
  // 显示哪些操作按钮
  operations: {
    type: Array,
    default: () => ['edit', 'delete', 'export']
    default: () => ["edit", "delete", "export"],
  },
  // 删除确认信息
  deleteConfirmText: {
    type: String,
    default: '确认删除该记录?'
  }
})
    default: "确认删除该记录?",
  },
  showOverflowTooltip: {
    type: Boolean,
    default: true,
  },
});
// 检查列是否需要显示tooltip
const shouldShowTooltip = (col, data) => {
  // 如果没有prop,直接返回false
  if (!col.prop) return false;
  // 检查该列在所有数据中是否有非空值
  return data.some(row => row[col.prop] != null && row[col.prop] !== '');
  return data.some((row) => row[col.prop] != null && row[col.prop] !== "");
};
// 处理单元格编辑
@@ -164,7 +224,8 @@
  if (!props.editableCells) return;
  // 如果指定了可编辑列,且当前列不在可编辑列中,则不允许编辑
  if (props.editableColumns.length > 0 && !props.editableColumns.includes(prop)) return;
  if (props.editableColumns.length > 0 && !props.editableColumns.includes(prop))
    return;
  // 初始化editing对象
  if (!row.editing) {
@@ -175,28 +236,29 @@
  // 在下一个DOM更新周期,让输入框获得焦点并选中内容
  setTimeout(() => {
    const inputElement = document.querySelector('.cell-edit .el-input__inner');
    const inputElement = document.querySelector(".cell-edit .el-input__inner");
    if (inputElement) {
      inputElement.focus();
      inputElement.select();
    }
  }, 10);
}
};
// 处理单元格保存
const handleCellSave = (row, prop) => {
  // 关闭编辑状态
  row.editing[prop] = false;
  // 触发单元格编辑完成事件
  emit('cell-edit', row, prop, row[prop]);
}
  emit("cell-edit", row, prop, row[prop]);
};
// 处理单元格聚焦事件
const handleCellFocus = (row, prop, event) => {
  // 如果不允许编辑单元格,直接返回
  if (!props.editableCells) return;
  // 如果指定了可编辑列,且当前列不在可编辑列中,则不允许编辑
  if (props.editableColumns.length > 0 && !props.editableColumns.includes(prop)) return;
  if (props.editableColumns.length > 0 && !props.editableColumns.includes(prop))
    return;
  // 初始化editing对象
  if (!row.editing) {
@@ -209,70 +271,75 @@
  if (event && event.target) {
    event.target.select();
  }
}
};
// 判断列是否可编辑
const isColumnEditable = (prop) => {
  if (props.editableColumns.length === 0) {
    return props.editableCells;
  }
  return props.editableColumns.includes(prop);
}
};
// 处理选择变化、编辑、删除和导出操作
const emit = defineEmits(['selection-change', 'edit', 'delete', 'export', 'cell-edit'])
const emit = defineEmits([
  "selection-change",
  "edit",
  "delete",
  "export",
  "cell-edit",
]);
const handleSelectionChange = (selection) => {
  emit('selection-change', selection)
}
  emit("selection-change", selection);
};
const handleEdit = (row) => {
  emit('edit', row)
}
  emit("edit", row);
};
const handleExport = (row) => {
  emit('export', row)
}
  </script>
  <style scoped lang="scss">
  emit("export", row);
};
</script>
<style scoped lang="scss">
.el-table {
    margin: 20px 0 !important;
  }
  :deep(.el-table th) {
    background-color: #f5f7fa;
  }
  :deep(.cell-edit) {
  margin: 20px 0 !important;
}
:deep(.el-table th) {
  background-color: #f5f7fa;
}
:deep(.cell-edit) {
  width: 100%;
  height: 100%;
  position: relative;
}
:deep(.cell-edit .cell-text) {
  width: 100%;
  display: block;
}
:deep(.cell-edit.editable:hover .cell-text) {
  color: #409eff;
  cursor: pointer;
}
:deep(.cell-input) {
  width: 80%;
  max-width: 120px;
  min-width: 60px;
}
:deep(.cell-input .el-input__inner) {
  border-radius: 4px;
  text-align: center;
  transition: all 0.2s;
}
/* 响应式样式 */
@media screen and (max-width: 768px) {
  :deep(.el-table) {
    width: 100%;
    height: 100%;
    position: relative;
    overflow-x: auto;
  }
  :deep(.cell-edit .cell-text) {
    width: 100%;
    display: block;
  }
  :deep(.cell-edit.editable:hover .cell-text) {
    color: #409EFF;
    cursor: pointer;
  }
  :deep(.cell-input) {
    width: 80%;
    max-width: 120px;
    min-width: 60px;
  }
  :deep(.cell-input .el-input__inner) {
    border-radius: 4px;
    text-align: center;
    transition: all 0.2s;
  }
  /* 响应式样式 */
  @media screen and (max-width: 768px) {
    :deep(.el-table) {
      width: 100%;
      overflow-x: auto;
    }
  }
</style>
}
</style>