Encapsulate an Element-ui to generate a table that can be edited within (vue2 project)

This encapsulates a table that is used by the entire project and can be reused multiple times. It is placed under a common component file for global use.

General function introduction, encapsulate custom instructions, click to get focus, display input box, lose focus to display text content, the type is determined by a dictionary, the picture can display the picture name or upload the picture

Subassembly

<script>
export default {
  props: {
    //Generate table header
    fields: {
      type: Array,
      default: () => [],
    },
    //data
    tableData: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {};
  },
  created() {},
//Custom instructions
  directives: {
    focus: {
      inserted: function (el) {
        el.querySelector("input").focus();
      },
    },
  },
  methods: {
    // Click the box to get focus column column, row row
    cellClick(column, row) {
      column.iseditor = true;
      row.isnameSelected = true;
    },
    //The input box loses focus and is triggered. Here, a prompt box is used to prompt for modification.
    blurEvent(column, row) {
      // console.log(column, row);
      column.iseditor = false;
      row.isnameSelected = false;
    },
   
  },
};
</script>
<template>
  <div>
    <el-table :data="tableData" border style="width: 100%">
      <el-table-column
        :prop="field.prop"
        :label="field.label"
        :min-width="field.minWidth || 140"
        v-for="(field, index) in fields"
        :key="index"
        show-overflow-tooltip
      >
        <template slot-scope="scope">
          <div v-if="field.slot">
            <slot :name="field.slot" :row="scope.row" />
          </div>
          <div v-else>
            <div>
              <el-input
                v-if="field.iseditor & amp; & amp; scope.row.isnameSelected"
                v-model="scope.row[field.prop]"
                @focus="cellClick(field, scope.row)"
                @blur="blurEvent(field, scope.row)"
                v-focus
              >
              </el-input>
              <p @click="cellClick(field, scope.row)" v-else>
                {<!-- -->{ scope.row[field.prop] || "--" }}
              </p>
            </div>
          </div>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>
<style scoped>
</style>
<style>
.el-tooltip__popper {
  max-width: 1000px;
}
.disabled .el-upload--picture-card {
  display: none;
}
.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.avatar-uploader .el-upload:hover {
  border-color: #409eff;
}
.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  line-height: 178px;
  text-align: center;
}
.avatar {
  width: 178px;
  height: 178px;
  display: block;
}
</style>

parent component

There is also a component that encapsulates file upload and is nested in the table, which is an expansion.

<script>
import editComponents from "../../components/editComponents";
export default {
  components: { editComponents },
  data() {
    return {
      fields: [
        {
          prop: "industryCode",
          label: "product",
          iseditor: false,
        },
        {
          prop: "id",
          label: "id",
          iseditor: false,
        },
        {
          prop: "paragraphType",
          label: "product type",
          iseditor: false,
          slot: "paragraphType",
//Decide whether to use the slot based on this slot, so that the parent component can better use the data without passing it around. The following is the same
        },
        {
          prop: "paragraphImage",
          label: "product picture",
          slot: "paragraphImage",
          iseditor: false,
        },
        {
          prop: "action",
          label: "operation",
          slot: "action",
        },
      ],
      tableData: [
        {
          industryCode: "Apple",
          id: "15",
          paragraphType: "1",
          paragraphImage: "15.png",
        },
        {
          industryCode: "Apple",
          id: "16",
          paragraphType: "2",
          paragraphImage: "15.png",
        },
        {
          industryCode: "Apple",
          id: "17",
          paragraphType: "1",
          paragraphImage: "15.png",
        },
      ],
      fileList: [], //Total number of files
      fileList1: [], //Total number of detailed files
      dialogImageUrl: "",
      dialogVisible: false,
      disabled: false,
    };
  },
  computed: {
    //File upload address
    upLoadUrl() {
      //process.env.VUE_APP_BASE_API detects the current environment to determine the interface path
      //Test environment VUE_APP_BASE_API = '/stage-api'
      if (process.env.VUE_APP_BASE_API == "/stage-api") {
        return "interface address"; // For example: '/minio/upload'
        // Production
      } else if (process.env.VUE_APP_BASE_API == "Production Interface") {
        return "interface address";
      } else {
        // local
        return "interface address";
      }
    },
  },
  created() {
    this.getlist();
  },
  methods: {
    //retrieve data
    getlist() {
      // Send a request to get data and write it here
      this.tableData = this.tableData.map((item) => {
        return { ...item, isnameSelected: false };
      });
    },
    // Add to
    hAdd() {
      const productObj1 = {
        industryCode: "",
        id: "",
        paragraphType: "",
        paragraphImage: "",
        iseditor: false,
        uuId: Math.random(),
      };

      this.tableData.push(productObj1);
    },
    // delete
    del(row) {
      this.tableData = this.tableData.filter(
        (item) => item.uuId !== row.uuId || item.id !== row.id
      );
    },
    //Image upload============================
    handleRemove(file) {
      console.log(file);
      console.log(this.$refs.upload);
      let uploadFiles = this.$refs.upload.uploadFiles;
      for (var i = 0; i < uploadFiles.length; i + + ) {
        if (uploadFiles[i]["url"] == file.url) {
          uploadFiles.splice(i, 1);
        }
      }
    },
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url;
      this.dialogVisible = true;
    },
    handleDownload(file) {
      console.log(file);
    },
    //File uploaded successfully-----------------
    async handleSuccess(response, row) {
      // Process the logic after successful upload
      console.log("Upload successful", response, row);
      this.fileName = response.data.fileName;
      row.paragraphImage = response.data.fileName;
    },
    handleError(err, file, fileList) {
      // Handle the logic after upload failure
      console.error("Upload failed", err);
    },
    // selectedLabel(selectedValue) {
    // if (selectedValue === "1") {
    // return "Choose one";
    // } else if (selectedValue === "2") {
    // return "Choice 2";
    // }
    // },
    async onSubmit() {
      // Delete unnecessary attributes
      this.tableData.forEach(function (obj) {
        if (obj.hasOwnProperty("iseditor")) {
          delete obj.iseditor;
        }
        if (obj.hasOwnProperty("uuId")) {
          delete obj.uuId;
        }
        if (obj.hasOwnProperty("isnameSelected")) {
          delete obj.isnameSelected;
        }
      });
      //Add
      if (!this.industryCode) {
        //Write new request here
        console.log(res);
        if (res.message == "success") {
          this.$message({
            message: res.data,
            type: "success",
            duration: 1000,
          });
        } else {
          this.$message.error(res.data);
        }
      } else {
        // Modification request is written here
        console.log(res);
        if (res.message == "success") {
          this.$message({
            message: res.data,
            type: "success",
            duration: 1000,
          });
          this.goBack();
        } else {
          this.$message.error(res.data);
        }
      }
    },
  },
};
</script>
<template>
  <div>
    <el-button @click="hAdd" type="primary">Add</el-button>
    <editComponents :fields="fields" :tableData="tableData">
      <template #action="{ row }">
        <el-button type="text" size="small" @click="del(row)">Delete</el-button>
      </template>
      <template #paragraphImage="{ row }">
        <div>
          <p>{<!-- -->{ row.paragraphImage || "--" }}</p>
          <el-upload
            ref="upload"
            :file-list="fileList1"
            :action="upLoadUrl"
            list-type="picture-card"
            :on-success="(e) => handleSuccess(e, row)"
            :on-error="handleError"
          >
            <i slot="default" class="el-icon-plus"></i>
            <div slot="file" slot-scope="{ file }">
              <img
                class="el-upload-list__item-thumbnail"
                :src="file.url"
                alt=""
              />
              <span class="el-upload-list__item-actions">
                <span
                  class="el-upload-list__item-preview"
                  @click="handlePictureCardPreview(file)"
                >
                  <i class="el-icon-zoom-in"></i>
                </span>

                <span
                  v-if="!disabled"
                  class="el-upload-list__item-delete"
                  @click="handleRemove(file)"
                >
                  <i class="el-icon-delete"></i>
                </span>
              </span>
            </div>
          </el-upload>
          <el-dialog :visible.sync="dialogVisible">
            <img width="100%" :src="dialogImageUrl" alt="" />
          </el-dialog>
        </div>
      </template>
      <template #paragraphType="{ row }">
        <div>
          <el-select v-model="row.paragraphType" placeholder="Please select">
            <el-option label="Choose one" value="1"></el-option>
            <el-option label="Choose Two" value="2"></el-option>
          </el-select>
          <!-- <p @click="cellClick(row)">
              {<!-- -->{ selectedLabel(row.titleTypeSecond) || "--" }}
              {<!-- -->{row}}
            </p> -->
        </div>
      </template>
    </editComponents>
    <el-card>
      <div>
        <el-button type="primary" round @click="onSubmit">Submit</el-button>
      </div>
    </el-card>
  </div>
</template>
<style scoped>
</style>