<组件封装:Vue + elementUi 通过excel文件实现 “ 批量导入 ” 表单数据,生成对应新增信息 >

news2024/11/6 9:41:20

标题图片

Vue + elementUi 通过excel文件实现 “ 批量导入 ” 表单数据,生成对应新增信息

  • 👉 前言
  • 👉 一、封装组件对应API及绑定事件
    • > Attributes
    • > Event
  • 👉 二、实现案例
    • > HTML父组件模板
    • > 子组件模板
  • 👉 三、效果演示
  • 往期内容 💨


👉 前言

在 Vue + elementUi 开发中,当某些新增表单数据过多时,为了提高新增数据的效率,往往会需要实现批量新增的功能。为此,我们就需要封装一个批量新增弹窗的功能组件,因实际场景需要,本次封装的批量导入组件,涵盖附件上传功能,组件仅以抛砖引玉! 需要按照实际应用场景进行调整!

👉 一、封装组件对应API及绑定事件

> Attributes

参数说明类型可选值默认值
url批量导入模板文件上传地址String-必填
title批量导入标题String-批量导入
uploadTableFileUrl模板导入列表数据中附件上传地址String-必填
restrictFileTypes模板文件可上传附件类型限制Array‘xlsx’, ‘xls’…文件类型[ ]
fileName模板文件流入参名称String-files
fileData模板上传参数DataObject-null
downFileName模板下载按钮文本String-下载
columnArray附件列表表头配置(需与后端沟通)Array-[ ]
tableTypeOpinion列表类型切换配置参数Array-[{label: ‘类型一’,value: ‘类型一’}…]
tableApi获取列表数据的Axios方法名称,需要按照应用场景封装的Axios请求方式修改组件内部代码String-必填
fileDeleteApi模板数据列表中的Axios方法名称,需要按照应用场景封装的Axios请求方式修改组件内部代码String-必填
uploadFileIdName列表附件上传入参时对应的ID名称String-id
rowFileIdName列表数据的ID名称,与uploadFileIdName 配合使用,uploadFileIdName 入的参数为rowFileIdName对应的值String-id
outSideDownFn父组件中对应的下载模板的方法名String-必填
outSideShowName外部引用子组件的显隐判断参数名String-showFileUp
showTableType控制是否显示列表类型切换功能Boolean-false
tableTypeName列表类型切换时,请求列表入参名String-tableType
importDataTips导入提示String-

> Event

方法名说明参数
tableTypeChange列表类型切换组件发生变更时触发change值
upLoadSuccess导入模板文件成功时触发文件上传接口返回res
getRow列表操作方法对应点击触发方法操作事件类型,与columnArray 配置中定义的配置相关
submit点击保存时触发请求参数

👉 二、实现案例

> HTML父组件模板

<!-- 批量导入 -->
<fileUploads
  ref="fileUploads"
  v-if="showFileUploads"
  outSideShowName="showFileUploads"
  title="批量导入核实数据"
  :downFileName="'已选中 ' + (multipleSelection.length || 0) + ' 条数据,点击下载模板'"
  fileName="excelFile"
  url="/disposal/modelOrder/batchCheck/importExcel"
  :fileData="{}"
  fileDeleteApi="knowledgeExcelImportDeleteFile"
  importDataTips="提示: 导入批量核实模板明细选项条数最多不能超过1000条"
  :columnArray="columnArray_file"
  :exportMark="'knowledge' + $route.query.itemIndex"
  uploadTableFileUrl="/disposal/modelOrder/batchCheck/uploadFile"
  tableApi="disposalModelOrderBatchCheckImportList"
  :restrictFileTypes="['xlsx', 'xls']"
  uploadFileIdName="id"
  outSideDownFn="fileModelDownFn"
  :showTableType="true"
  :tableTypeOpinion="[
    {
      label: '非缺陷',
      value: 1
    },
    {
      label: '缺陷',
      value: 2
    }
  ]"
  tableTypeName="tableType"
  @tableTypeChange="getColumnArray_batch"
  @upLoadSuccess="upLoadSuccess($event)"
  @getRow="getRow"
  @submit="fileUploadsSubmit"
/>

// 数据
columnArray: [
	{
	  prop: "problemCode",
	  label: "问题编号",
	  width: "150",
	},
	{
	  prop: "problemFindTime",
	  label: "问题发现时间",
	  width: "165",
	},
	{
	  prop: "problemDescription",
	  label: "问题具体描述",
	  width: "160",
	},
	{
	  prop: "problemExistOrgName",
	  label: "问题整改情况",
	  width: "140",
	},
	{
	  type: "files",
	  prop: "files",
	  label: "附件名称",
	  width: "140",
	  showOverflowTooltip: false,
	},
	{
	  type: "uploadFile",
	  prop: "files",
	  label: "上传附件",
	  width: "140",
	},
	{
	  type: "operate",
	  linkName: ["删除"],
	  label: "操作",
	  width: "100",
	},
],
// 方法
<script>
// 获取表格表头
async getColumnArray_batch(type, fn = () => {}) {
 const res = await this.getDictionaryHeader({
   code: 'batch-' + type,
   ssywy: this.paramsInfo.data.ywy
 })
 
 if (Array.isArray(res) && res.length !== 0) {
   this.columnArray_file = [
     ...res,
     // {
     //   type: "uploadFile",
     //   prop: "files",
     //   label: "上传附件",
     //   width: "140",
     // },
     {
       type: "operate",
       linkName: ["删除"],
       label: "操作",
       width: "100",
     },
   ]
   fn()
 } else {
   this.columnArray_file = []
   this.$message.warning('批量核实需上传列表表头获取失败,请重试!')
 }
 return false;
},
// 批量核实部分代码
// 批量导入 - 导入文件成功
upLoadSuccess(res) {
  this.$refs["fileUploads"].initTable({
    versionId: res.data,
    ssywy: this.paramsInfo.data.ywy
  });
},
// 批量导入表格操作
getRow(row, type) {
  if (type == "删除") {
    this.disposalModelOrderBatchCheckImportListDelete({
      knowledgeId: row.id,
    }).then(() => {
      // window.console.log(res)
      this.$message.success("删除成功!");
      this.$refs["fileUploads"].initTable();
    });
  } else if (type == "下载") {
    // this.downloadFile(row)
  }
},
// 批量导入提交
fileUploadsSubmit(params) {
  let _params = new URLSearchParams();
  for (let key in params) {
    _params.append(key, params[key]);
  }
  this.disposalModelOrderBatchCheckSubmit(_params)
    .then(() => {
      // window.console.log(res)
      this.$message.success("批量导入成功!");
      this.$refs["fileUploads"].closeDialog();
      this.getDocumentQuery();
    })
    .catch((err) => {
      this.$message.warning(err.message || "请求出错,请检查后重试!");
    });
},
</script>

> 子组件模板

<template>
  <div
    :class="
      $root.themeHomeChange === '1'
        ? 'fileUpload fileUpload_light'
        : 'fileUpload'
    "
  >
    <bda-dialog
      :visible="dialogVisible"
      :modal="false"
      :close-on-click-modal="false"
      @cancel="closeDialog"
      @close="closeDialog"
      :title="title"
      :modal-append-to-body="false"
    >
      <div class="dialogBox">
        <div class="header">
          <el-row
            style="font-size: 1.125rem; line-height: 30px; padding: 15px 15px 0;"
          >
            <el-col :span="12" class="upload-box">
              <span class="title">导入数据:</span>
              <el-upload
                ref="uploaddemo"
                class="upload-demo"
                :limit="1"
                :data="fileData"
                :name="fileName"
                :action="fileUrl"
                :multiple="false"
                :on-change="handleChange"
                :on-exceed="handleExceed"
                :before-upload="beforeAvatarUpload"
                :on-success="handleAvatarSuccess"
                :show-file-list="false"
                :file-list="fileList"
              >
                <el-button size="mini" style="margin-left:10px">上传</el-button>
              </el-upload>
              <span class="text" v-if="fileList.length">
                已上传:
                <span v-for="(item, index) in fileList" :key="index">
                  {{ item.name }}
                  <el-button
                    type="text"
                    @click="handleClick('remove', item, index)"
                    >删除</el-button
                  >
                </span>
              </span>
            </el-col>
            <el-col :span="12">
              <span class="title">模板下载:</span>
              <el-button
                size="mini"
                :loading="exportLoading"
                @click="handleClick('down')"
              >{{ downFileName }}</el-button>
            </el-col>
          </el-row>
          <el-row
            style="font-size: 1.125rem; line-height: 30px; padding: 15px 15px 0;"
          >
            <span class="title">导入结果:</span>
            <strong v-if="importData !== 0">导入成功,导入数据{{ importData }}条</strong>
            <strong v-else>暂无导入文件,请先导入文件!</strong>
            <p v-if="!!importDataTips" style="margin: 8px 0 0 0; color: #fc6271; font-weight: bold;">{{  importDataTips }}</p>
          </el-row>
        </div>
        <div class="line"></div>
        <div class="tableHeader_1">
          <span class="name">需上传附件列表</span>
          <el-radio-group
            v-model="params[tableTypeName]"
            v-if="showTableType"
            @change="tableTypeChange"
          >
            <el-radio-button
              v-for="(item, index) in tableTypeOpinion"
              :key="index"
              :label="item.value"
            >{{ item.label }}</el-radio-button>
          </el-radio-group>
        </div>
        <el-table
          v-loading="tableLoading"
          element-loading-text="拼命加载中"
          element-loading-spinner="el-icon-loading"
          element-loading-background="rgba(0, 0, 0, 0.8)"
          :data="tableData"
          row-key="knowledgeId"
          ref="table"
          tooltip-effect="light"
          height="300"
          popper-append-to-body
        >
          <el-table-column
            type="index"
            label="序号"
            width="70"
            align="center"
          ></el-table-column>
          <el-table-column
            v-for="(item, index) in columnArray"
            :show-overflow-tooltip="
              item.showOverflowTooltip == undefined
                ? true
                : item.showOverflowTooltip
            "
            :key="index"
            :prop="item.prop"
            :label="item.label"
            :min-width="item.width"
            align="center"
          >
            <template slot-scope="scope">
              <span v-if="item.type === 'operate'">
                <el-button
                  type="text"
                  v-for="item2 in item.linkName"
                  :key="item2"
                  @click="rowClick(scope.row, item2)"
                  >{{ item2 || "" }}</el-button
                >
              </span>
              <template v-else-if="item.type === 'files'">
                <el-popover
                  popper-class="popoverClass_light"
                  v-if="scope.row[item.prop].length !== 0"
                  placement="top-start"
                  width="200"
                  trigger="hover"
                >
                  <div
                    class="table_file"
                    v-for="(item_1, index_1) in scope.row[item.prop]"
                    :key="index_1"
                    @click="rowClick(item_1, '下载')"
                  >
                    {{ "附件 [" + (index_1 + 1) + "]: " + item_1.fileName }}
                  </div>
                  <p slot="reference" class="fileTitle">
                    {{ "附件 [1]: " + scope.row[item.prop][0].fileName }}
                  </p>
                </el-popover>
                <p v-else>暂无数据</p>
              </template>
              <template v-else-if="item.type === 'uploadFile'">
                <el-button @click="showUploadFileDialog(scope.row, scope.row[item.prop])" >{{ scope.row[item.prop].length !== 0 ? '修改已上传文件' : '选择文件' }}</el-button>
              </template>
              <span v-else>{{ scope.row[item.prop] }}</span>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination
          :disabled="params.total == 0"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="params.current"
          :page-sizes="[10, 50, 100, 200]"
          :page-size="params.size"
          background
          layout="prev, pager, next, sizes, jumper, total"
          :total="params.total"
        ></el-pagination>
        <el-dialog
          title="附件操作"
          :modal="false"
          :visible.sync="innerVisible"
          custom-class="uploadFiles"
        >
          <el-input
            v-show="false"
            v-model="tableFileParams.fileTable.length">
          </el-input>
          <p style="font-size: 12.5px; line-height: 25px; margin-bottom: 10px;">
            (单个文件大小不能超过50M,仅支持 xls、xlsx、doc、docx、pdf 格式)
          </p>
          <el-upload
            class="upload-demo"
            name="files"
            ref="uploaddemo_table"
            :action="tableFileParams.fileUrl"
            :data="tableFileParams.data"
            :on-change="handleChange_table"
            :before-upload="beforeAvatarUpload_table"
            :on-success="handleAvatarSuccess_table"
            :file-list="tableFileParams.fileList"
          >
            <el-button
              size="small"
              plain
            >上传附件</el-button>
          </el-upload>
          <el-table
            :data="tableFileParams.fileTable"
            style="width: 100%; margin-top: 10px;"
            height="calc(170px)"
            v-loading="tableFileParams.fileTableLoading"
            tooltip-effect="light"
            element-loading-text="拼命加载中"
            element-loading-spinner="el-icon-loading"
            element-loading-background="rgba(0, 0, 0, 0.8)"
          >
            <el-table-column
              type="index"
              label="序号"
              width="60"
              align="center"
            ></el-table-column>
            <el-table-column
              prop="fileName"
              label="附件名称"
              min-width="120"
              align="center"
              show-overflow-tooltip>
            </el-table-column>
            <el-table-column
              prop="fileType"
              label="类型"
              width="120"
              align="center"
              show-overflow-tooltip>
            </el-table-column>
            <el-table-column
              label="操作"
              width="100"
              align="center"
            >
              <template slot-scope="scope">
                <el-button
                  type="text"
                  style="margin-left: 0;"
                  @click="deleteFile(scope.row)"
                > 删除 </el-button>
              </template>
            </el-table-column>
          </el-table>
          <span slot="footer" class="dialog-footer">
            <el-button @click="tableFileSubmit" type="primary">保 存</el-button>
            <bda-button bdatype="defualt" @click="closeFileDialog">关闭</bda-button>
          </span>
        </el-dialog>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="submit()" type="primary">保 存</el-button>
        <bda-button bdatype="defualt" @click="closeDialog">关闭</bda-button>
      </span>
    </bda-dialog>
  </div>
</template>

<script>
import Interface from "@/base/mixin/enterprise-manage-center";
import Interface_1 from "@/base/mixin/risk-control-center";
import Interface_2 from "@/base/mixin/disposal-center.js";
import { API_PATH } from "@/config";
export default {
  name: "historyDoc",
  mixins: [Interface, Interface_1, Interface_2],
  props: {
    // 导入模板附件Url
    url: {
      type: String,
      required:true,
      default: () => {
        return "";
      },
    },
    // 列表附件上传API名称
    uploadTableFileUrl: {
      type: String,
      required:true,
      default: () => {
        return "";
      },
    },
    // 可上传附件类型
    restrictFileTypes: {
      type: Array,
      default: () => {
        return [];
      },
    },
    // 附件上传的附件参数名
    fileName: {
      type: String,
      default: () => {
        return "files";
      },
    },
    // 附件上传参数
    fileData: {
      type: Object,
      default: () => {
        return null;
      },
    },
    // 标题
    title: {
      type: String,
      default: () => {
        return "批量导入";
      },
    },
    // 下载模板提示文字
    downFileName: {
      type: String,
      default: () => {
        return "下载";
      },
    },
    // 动态表头配置项
    columnArray: {
      type: Array,
      required:true,
      default: () => {
        return [];
      },
    },
    // 列表类型切换配置项
    tableTypeOpinion: {
      type: Array,
      required:false,
      default: () => {
        return [
          {
            label: '类型一',
            value: '类型一'
          },
          {
            label: '类型二',
            value: '类型二'
          }
        ];
      },
    },
    // 导出模板备注,用于区分多种模板时区分模板类型
    exportMark: {
      type: String,
      default: () => {
        return '';
      },
    },
    // 获取列表数据API名称
    tableApi: {
      type: String,
      required:true,
      default: () => {
        return '';
      },
    },
    // 附件删除API名称
    fileDeleteApi: {
      type: String,
      required:true,
      default: () => {
        return '';
      },
    },
    // 对应列表项的id
    uploadFileIdName: {
      type: String,
      default: () => {
        return 'id';
      },
    },
    // 列表项对应的附件ID名称,用于绑定附件操作等
    rowFileIdName: {
      type: String,
      default: () => {
        return 'id';
      },
    },
    // 外部模板下载方法(名称)
    outSideDownFn: {
      type: String,
      required:true,
      default: () => {
        return null;
      },
    },
    // 外部入参
    inParams: {
      type: Object,
      default: () => {
        return {};
      },
    },
    // 是否显示列表类型切换
    showTableType: {
      type: Boolean,
      default: () => {
        return false;
      },
    },
    // 导入提示
    importDataTips: {
      type: String,
      default: () => {
        return null;
      },
    },
    // 列表类型切换入参名称
    tableTypeName: {
      type: String,
      default: () => {
        return 'tableType';
      },
    },
    // 外部控制显隐的字段,用于重新触发组件加载
    outSideShowName: {
      type: String,
      default: () => {
        return 'showFileUp';
      },
    },
  },
  data() {
    return {
      exportLoading: false,
      tableLoading: false,
      importData: 0,
      dialogVisible: false,
      innerVisible: false,
      fileUrl: null,
      fileList: [],
      tableData: [],
      // tableType: null,
      in_Params: {},
      params: {
        current: 1,
        size: 10,
        total: 0,
      },
      tableFileParams: {
        fileTable: [],
        fileTableLoading: false,
        fileList: [],
        data: {},
        fileUrl: ''
      }
    };
  },
  created() {
    this.fileUrl = API_PATH + this.url;
    this.tableFileParams.fileUrl = API_PATH + this.uploadTableFileUrl;
    if(this.showTableType) {
      window.console.log(1231)
      this.params[this.tableTypeName] = this.tableTypeOpinion.length !== 0 ? this.tableTypeOpinion[0].value : null
    }
  },
  mounted() {},
  methods: {
    /**
     * @description:关闭弹框回调
     */
    closeDialog() {
      this.dialogVisible = false;
      this.$parent[this.outSideShowName] = false;
      this.initData()
    },
    // 初始化数据
    initData() {
      this.in_Params = {};
      this.tableData = []
      this.fileList = []
      this.importData = 0
      this.params = {
        current: 1,
        size: 10,
        total: 0,
      }
    },
    // 切换表格类型
    tableTypeChange() {
      this.$emit('tableTypeChange', this.params[this.tableTypeName])
      if(this.fileList.length !== 0) {
        this.initTable()
      }
    },
    // 展示附件操作弹窗 并 进行参数传递
    showUploadFileDialog(row, fileList) {
      this.tableFileParams.data = {
        ...this.in_Params,
        [this.uploadFileIdName]: row[this.rowFileIdName]
      }
      this.tableFileParams.fileTable = fileList.map(item => {
        return {
          ...item,
          fileType: item.fileType || (item.filePath && item.filePath.substring(item.filePath.lastIndexOf(".")+1))
        }
      })
      this.innerVisible = true
    },
    rowClick(row, op) {
      if (op === "删除") {
        this.$confirm("此操作将删除该数据, 是否继续?", "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
        }).then(() => {
          window.console.log(row, op)
          this.$emit("getRow", row, op);
        })
      } else {
        this.$emit("getRow", row, op);
      }
    },
    //文件上传成功钩子
    handleAvatarSuccess(res) {
      if (res.success) {
        this.$message.success("上传成功");
        this.$emit("upLoadSuccess", res);
      } else {
        this.$message.warning(
          "上传失败, 失败原因:" +
            ((res.message || res.code) ? (res.message || res.code) : "未知")
        );
        this.$refs.uploaddemo.clearFiles();
      }
    },
    //文件上传之前钩子
    beforeAvatarUpload(file) {
      window.console.log(file.name.split(".")[file.name.split(".").length - 1]);
      // 限制文件格式类型
      // const isDocx = file.name.split('.')[1] === 'docx'
      const flag = this.restrictFileTypes.some((item) => {
        return file.name.split(".")[file.name.split(".").length - 1] === item;
      });

      if (!flag && this.restrictFileTypes.length !== 0) {
        this.$message({
          message: "请上传指定类型的文件!",
          type: "error",
        });
        // this.$forceUpdate();
        return false;
      }
      // 限制文件上传大小
      const isLt10M = file.size / 1024 / 1024 < 128;
      if (!isLt10M) {
        this.$message.error("上传文件大小不能超过 128MB!");
        // this.$forceUpdate();
        return false;
      }
    },
    handleChange(file, fileList) {
      this.fileList = fileList.slice(-1);
    },
    // 提交表单
    submit() {
      if(this.fileList.length !== 0) {
        this.$emit('submit', this.in_Params)
      } else {
        this.$message.warning('请先导入对应模板的数据文件!')
      }
    },
    tableFileSubmit() {
      let prop = this.columnArray.find(item => item.type == 'uploadFile').prop
      this.tableData.forEach(item => {
        if(item[this.rowFileIdName] == this.tableFileParams.data[this.uploadFileIdName]) {
          // window.console.log(item.id, this.tableFileParams.data[this.uploadFileIdName])
          item[prop] = JSON.parse(JSON.stringify(this.tableFileParams.fileTable))
        }
      })
      this.$nextTick(() => {
        this.closeFileDialog()
      });
    },
    handleClick(type, item, index) {
      // window.console.log(type);
      if (type === "remove") {
        this.$confirm("此操作将清空批量导入的文件及列表数据, 是否继续?", "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
        }).then(() => {
          this.fileList.splice(index, 1);
          this.initData()
        })
      } else if(type === "down") {
        if(this.outSideDownFn) {
          this.$parent[this.outSideDownFn]()
        } else {
          window.location.href = `${API_PATH}/dictionary/template?exportMark=${this.exportMark}`;
        }
      }
    },
    // 删除附件内容
    deleteFile(row) {
      this.$confirm("此操作将删除该附件, 是否继续?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(() => {
        this[this.fileDeleteApi]({ fileId: row.fileId }).then(() => {
          this.tableFileParams.fileTable.splice(this.tableFileParams.fileTable.indexOf(row), 1)
          this.$message.success('删除成功!')
          // 删除后同步到列表中
          this.$nextTick(() => {
            let prop = this.columnArray.find(item => item.type == 'uploadFile').prop
            this.tableData.forEach(item => {
              if(item[this.rowFileIdName] == this.tableFileParams.data[this.uploadFileIdName]) {
                item[prop] = JSON.parse(JSON.stringify(this.tableFileParams.fileTable))
              }
            })
          });
        }).finally(() => {})
      })
    },
    //文件上传成功钩子
    handleAvatarSuccess_table(res) {
      window.console.log(res)
      if (res.success){
        this.$message.success('上传成功');
        this.getFileList(res.data)
        this.tableFileParams.fileList = [];
        setTimeout(() => {
          this.$refs.uploaddemo_table.clearFiles();
        }, 1000);
      } else {
        this.$message.warning(res.code === '400' || res.code === '500' ? res.message : '上传失败,请重试!');
        this.$refs.uploaddemo_table.clearFiles();
      }
    },
    // 附件表格
    getFileList(files) {
      this.tableFileParams.fileTableLoading = true;
      this.tableFileParams.fileTable.push(...files);
      setTimeout(() => {
        this.tableFileParams.fileTableLoading = false;
      }, 1000)
    },
    //文件上传之前钩子
    beforeAvatarUpload_table() {
     return true
    },
    handleChange_table(file, fileList) {
      this.tableFileParams.fileList = fileList.slice(-1);
    },
    handleSizeChange(val) {
      // window.console.log(`每页 ${val} 条`);
      this.params.size = val;
      this.initTable();
    },
    handleCurrentChange(val) {
      // window.console.log(`当前页: ${val}`);
      this.params.current = val;
      this.initTable();
    },
    handleExceed() {
      this.$message.warning(`选择上传文件超出限制!`);
    },
    // 附件上传弹窗关闭
    closeFileDialog() {
      this.innerVisible = false
      this.tableFileParams.data = {}
      this.tableFileParams.fileTable = []
    },
    initTable(inParams = {}) {
      this.in_Params = {...inParams, ...this.in_Params}
      if(!this.tableApi) {
        this.$message.warning(`请先配置对应的列表请求API!`);
        return
      }
      this.tableLoading = true
      this[this.tableApi]({
        ...this.params,
        ...this.in_Params
      }).then(res => {
        this.tableData = res.rows
        this.params.total = res.records
        this.importData = this.importData === 0 ? res.records : this.importData
      }).finally(() => {
        this.tableLoading = false
      })
    },
  },
};
</script>

<style lang="scss">
.table_file {
  line-height: 20px;
  cursor: pointer;
  color: #333;
  transition: all 0.3s;
  &:hover {
    color: #66b9ff;
  }
}
.fileTitle {
  display: block;
  width: 100%!important;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
// popover 弹窗样式 浅色
.popoverClass_light {
  min-width: 176px;
  max-width: calc(30vw + 24px);
  // max-height: calc(25vh + 24px);
  .el-popover__title {
    font-family: MicrosoftYaHei-Bold;
    font-size: 12.5px;
    color: #666;
    font-weight: 700;
  }
  .tableFile {
    display: flex;
    justify-content: space-between;
    padding-left: 5px;
    transition: all 0.3s;
    .name {
      width: 240px;
      // max-width: 800px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      color: #666;
      &:hover {
        color: #66b9ff;
      }
    }
    .btn {
      display: flex;
      justify-content: space-around;
      align-items: center;
      width: 60px;
      font-size: 16px;
      font-weight: bold;
      color: #b8c9e6;
    }
  }
}
</style>

<style scoped lang="scss">
.fileUpload {
  /deep/ {
    // 修改分页组件样式
    .el-pagination {
      margin-top: 20px;
      text-align: center;
      color: #fff;
      .btn-next,
      .btn-prev,
      .el-pager li,
      .el-select .el-input .el-input__inner,
      .el-pagination__editor.el-input .el-input__inner {
        background: rgba(67, 137, 249, 0.06);
        color: #333333;
        border: 0px solid #2a5cb0;
        border-radius: 4px;
      }
      .el-pager li:not(.disabled).active {
        background-color: #4389f9;
      }
      .el-pagination__jump,
      .el-pagination__total {
        color: #545454;
        margin-left: 10px;
      }
    }
    .line {
      height: 1px;
      margin: 15px 15px 0;
      // background: #ccc;
      border-bottom: 1px solid #d9d9d9;
    }
    .el-dialog__wrapper {
      // background-color: rgba(0,0,0,0.4)
    }
    .uploadFiles {
      width: 650px!important;
      height: auto!important;
      margin-top: calc(50vh - 150px)!important;
      .el-dialog__header {
        border-bottom: 1px solid #4389f9 !important;
        height: 48px !important;
      
        .el-dialog__headerbtn {
          font-family: MicrosoftYaHei-Bold;
          font-size: 16px !important;
          color: #ffffff !important;
          line-height: 30px;
          font-weight: 700;
        }
      }
      .el-dialog__body {
        padding: 15px!important;
        height: 250px;
        overflow-y: auto;
      }
    }
    /*修改添加模型弹窗 */
    .el-dialog {
      width: 994px;
      height: 540px;
      background: #1f2c4d !important;
      border: 1px solid #4389f9;
      border-radius: 4px;
      .el-dialog__header {
        border-bottom: 1px solid #4389f9 !important;
        height: 48px !important;

        .bda-dialog-header .bda-dialog-header-title {
          font-family: MicrosoftYaHei-Bold;
          font-size: 16px !important;
          color: #ffffff !important;
          line-height: 48px;
          font-weight: 700;
        }
      }

      .bda-dialog-body-main {
        height: 438px !important;

        .el-form {
          .el-row:nth-of-type(3) {
            height: 80px;
            .el-textarea__inner {
              height: 60px;
              background: #041338;
              border: 1px solid #4389f9;
              color: #4298f3;
              &::placeholder {
                font-family: MicrosoftYaHei;
                font-size: 14px;
                color: #4298f3;
                font-weight: 400;
              }
            }
          }

          .el-row:nth-of-type(4) {
            height: 110px;
            .el-textarea__inner {
              height: 90px;
              background: #041338;
              border: 1px solid #4389f9;
              color: #4298f3;
              &::placeholder {
                font-family: MicrosoftYaHei;
                font-size: 14px;
                color: #4298f3;
                font-weight: 400;
              }
            }
          }
        }
      }

      .el-dialog__footer {
        border-top: 1px solid #4389f9 !important;
        height: 52px !important;

        .dialog-footer {
          display: block;
          height: 100%;
          padding: 11px 20px;
          box-sizing: border-box;
        }
      }
    }
    /*修改表格单元格高度*/
    .bda-pagination-table {
      .bda-pagination-table-page {
        border: 0 !important;
        height: 50px !important;
      }
      .bda-pagination-table-main {
        height: calc(100% - 40px);
      }
    } /*解决调整单元格高度后,fixed错位*/
    .el-table__fixed-body-wrapper {
      top: 37px !important;
    }

    /*解决表格滚动高度固定导致的异常*/
    .el-table__body-wrapper.is-scrolling-left {
      height: calc(100% - 48px) !important;
    }
    .el-table__body-wrapper.is-scrolling-right {
      height: calc(100% - 48px) !important;
    }
    .el-table__body-wrapper.is-scrolling-middle {
      height: calc(100% - 48px) !important;
    }
    .el-table__fixed-body-wrapper {
      height: calc(100% - 34px) !important;
    }

    /*解决调整列宽度时,出现列内容未完整显示的异常*/
    .el-table .cell.el-tooltip {
      width: 100% !important;
    }

    .el-table__header-wrapper {
      background-color: #fff !important;
    }

    .el-table__body-wrapper {
      background-color: #fff !important;
    }

    .el-table__header th {
      // background-color: #22519c !important;
      background: #e9f1fe !important;
      height: 48px;
      border-color: #bbb;

      .cell {
        color: #666 !important;
        text-align: center;
      }
    }
    .bda-table-main {
      background-color: #ffffff;
    }

    .bda-main {
      /*height: calc(100% - 52px);*/
      border: 1px solid #bbb;
      .el-table__row {
        &:hover > td {
          background-color: #ebfcff !important;
        }
        > td {
          height: 48px;
          border-color: #bbb;

          .cell {
            color: #333;
            text-align: center;
            .el-button {
              color: #66b9ff;
            }
          }
        }
        > td:nth-last-child(3) {
          .cell {
            /*color: red;*/
            text-align: center;
          }
        }
      }
      .el-table__row:nth-of-type(odd) {
        background-color: #fff;
      }
      .el-table__row:nth-of-type(even) {
        background-color: #fff;
      }
      .bda-table {
        .bda-table-scroll_x {
          height: 8px !important;
        }
        .bda-table-scroll_x_view {
          height: 8px !important;
          background-color: #b0b1b2 !important;
        }
      }
    }
  }
  .title {
    text-align: left!important;
  }
  .upload-box {
    display: flex;
    .text {
      margin-left: 10px;
    }
  }
  h2 {
    font-size: 16px;
    color: #333333;
    font-weight: 700;
  }
  .dialogBox {
    padding-bottom: 15px;
    .tableHeader_1 {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 10px 0;
      .name {
        font-size: 14px;
        font-weight: bold;
        color: #333;
      }
      /deep/ {
        .el-radio-group {
          /* // border: 1px solid #4389F9 ; */
          margin: 0 -1px;
          border-radius: 5px;
          .el-radio-button {
            margin-bottom: 5px;
            .el-radio-button__inner {
              border: 1px solid #4389F9;
              margin-right: -1px;
            }
            &:first-child {
              .el-radio-button__inner {
                border-top-left-radius: 5px;
                border-bottom-left-radius: 5px;
              }
            }
            &:last-child {
              .el-radio-button__inner {
                border-top-right-radius: 5px;
                border-bottom-right-radius: 5px;
              }
            }
          }
          .el-radio-button:not(.is-active) {
            .el-radio-button__inner {
              color: #333;
              border-color: #4389f9;
              background-color: rgba($color: #fff, $alpha: 1);
            }
          }
          .el-radio-button.is-active {
            .el-radio-button__inner {
              border-color: #4389f9;
              background-color: rgba($color: #4389f9, $alpha: 1);
              color: #fff;
            }
          }
        }
      }
    }
  }
}
.fileUpload_light {
  /deep/ {
    .el-dialog {
      background: #ffffff !important;
      border: 1px solid #c2ddff;
      border-radius: 4px;

      .el-dialog__header {
        border-bottom: 1px solid #cccccc !important;
        height: 48px !important;

        .bda-dialog-header .bda-dialog-header-title {
          font-family: MicrosoftYaHei-Bold;
          font-size: 16px !important;
          color: #333333 !important;
          line-height: 48px;
          font-weight: 700;
        }
      }
      .el-dialog__footer {
        border-top: 1px solid #cccccc !important;
        height: 52px !important;

        .dialog-footer {
          display: block;
          height: 100%;
          padding: 11px 20px;
          box-sizing: border-box;
        }
      }
    }
  }
}
</style>

案例较为粗浅,仅供参考!

👉 三、效果演示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


往期内容 💨

🔥 < 每日小技巧: 基于Vue状态的过渡动画 - Transition 和 TransitionGroup>

🔥 < 每日份知识快餐:axios是什么?如何在Vue中 封装 axios ? >

🔥 < 在Vue中 el-popover + el-tiptap 实现 富文本框输入,表格点击展示 (富文本HTML标签渲染) >

🔥 < 知识拓展:CSS 中常用的计量单位有哪些? >

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/544949.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

线程相关基础知识

一、相关概念 1.1 cpu 中央处理器&#xff08;central processing unit, 简称cpu &#xff09;&#xff0c;计算机系统的 运算 和 控制 核心 1.2 cpu核心数和线程数 cpu核心数指cpu 内核数量&#xff0c;如双核、四核、八核。 cpu线程数是一种逻辑的概念&#xff0c;就是模…

基于 SpringBoot + Redis 实现分布式锁

大家好&#xff0c;我是余数&#xff0c;这两天温习了下分布式锁&#xff0c;然后就顺便整理了这篇文章出来。文末附有源码链接&#xff0c;需要的朋友可以自取。 至于什么是分布式锁&#xff0c;这里不做赘述&#xff0c;不了解的可以自行去查阅资料。 文章目录 实现要点项目…

android13 FLAG_BLUR_BEHIND 壁纸高斯模糊,毛玻璃背景方案设计-千里马framework实战

hi,粉丝朋友们! 今天有个学员朋友&#xff0c;问到了一个高斯模糊相关问题&#xff0c;这个高斯模糊相关的需求我相对还是比较熟悉&#xff0c;下面来重点讲解一下新版本高斯模糊相关的实现。 更多framework干货知识手把手教学 Log.i("qq群"&#xff0c;“422901085…

[230528] 托福阅读真题|TPO66 13/30|整卷得分22/30|9:45~10:45|15:40~16:40

The Actor and the Audience P1 rehearsev 排练&#xff1b;排演anticipate v 预期&#xff1b;预料&#xff1b;预见 audiencen 观众brilliantadj 灿烂的&#xff1b;绝妙的rehearsaln 排练&#xff1b;预演&#xff1b;排演crumblev 崩塌stage frightn 怯场&#xff08;演员…

自动化测试框架?这应该是全网最全自动化框架总结了,你要的都有...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Python自动化测试&…

学术加油站|基于LSM-tree存储系统的内存管理,最大限度降低I/O成本

本文系北京理工大学科研助理牛颂登所著&#xff0c;本篇也是 OceanBase 学术系列稿件第 10 篇。欢迎访问 OceanBase 官网获取更多信息&#xff1a;https://www.oceanbase.com/ 「牛颂登&#xff1a;北京理工大学科研助理&#xff0c;硕士期间在电子科技大学网络空间安全研究院从…

资深老鸟总结,Selenium自动化测试实战小技巧,不要再走弯路了...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Selenium4自动化测…

数据库小技能:数据报表

文章目录 I 需求1.1 补贴II 实现思路2.1 生成资金调节报表数据III Dto3.1 报表基本查询IV 接口I 需求 代理商调节活动汇总商户调节活动汇总激励金日月汇总数据源:活动流水表(上游回调) 1.1 补贴 调节活动补贴= D0补贴+T1补贴。(比如交易金额满足1000,转T1) 补贴金额 =…

图扑数字孪生智慧灯杆,“多杆合一”降本增效

前言 随着智慧城市建设的不断深入&#xff0c;智慧灯杆作为城市基础设施的重要组成部分&#xff0c;正在成为城市智能化和绿色化的重要手段之一。 效果展示 图扑智慧灯杆系统在城市道路照明领域引入信息化手段&#xff0c;通过构建路灯物联网&#xff0c;实现了现代化的路灯按…

线性代数 --- Gram-Schmidt, 格拉姆-施密特正交化(下)

Gram-Schmidt正交化过程 到目前为止&#xff0c;我们都是在反复强调“对于无解的方程组Axb而言&#xff0c;如果矩阵A是标准正交矩阵的话&#xff0c;就怎么怎么好了。。。。”。因为&#xff0c;不论是求投影还是计算最小二乘的正规方程&#xff0c;他们都包含了。当A为标准正…

yolov4论文解读

数据层面上的数据增强 四张照片拼接成一张进行训练 相当于增大了batch-size&#xff0c;更适合于单GPU。 Mosaic data augmentation 马赛克数据增强 self-adversarial training(SAT) 自我对抗训练 DropBlock Label Smoothing 损失函数 由IOU改进到CIOU 网络结构 CSPNet&…

Win10 WLAN驱动正常但仍然不显示无线网络解决办法

Win10 WLAN驱动正常但仍然不显示无线网络解决办法 写作背景过程解决方案结尾 写作背景 本菜鸡重置了电脑的网络&#xff0c;然后重新启动后 WLAN 不见了&#xff0c;连不了 WIFI 了&#xff0c;很疑惑&#xff0c;后来经过一番搜索找到了问题所在&#xff0c;写下本篇文章以记…

Spark/Flink广播实现作业配置动态更新

前言 在实时计算作业中&#xff0c;往往需要动态改变一些配置&#xff0c;举几个栗子&#xff1a; 实时日志ETL服务&#xff0c;需要在日志的格式、字段发生变化时保证正常解析&#xff1b;实时NLP服务&#xff0c;需要及时识别新添加的领域词与停用词&#xff1b;实时风控服…

访问学者J1签证面签的七个问题

作为访问学者&#xff0c;申请J1签证面签时可能会遇到一些常见问题。下面知识人网小编将介绍七个访问学者面签可能遇到的问题&#xff0c;并提供相应的答案。 问题一&#xff1a;您将在美国进行何种类型的学术研究&#xff1f; 答案&#xff1a;我将在美国从事学术研究&#x…

普冉PY32L020单片机简介,主频最高48MHZ

PY32L020单片机是一颗32 位 ARM Cortex-M0内核&#xff0c;宽电压工作范围的 MCU。这颗MCU的价格跟八位单片机相差不大&#xff0c;性价比可以说是非常的高了。来看看PY32L020的配置吧。 PY32L020单片机产品特性&#xff1a; 内核&#xff1a; — 32 位 ARM Cortex - M0 — 最…

飞浆AI studio人工智能课程学习(2)-Prompt优化思路|十个技巧高效优化Prompt|迭代法|Trick法|通用法|工具辅助

文章目录 优化思路上节课的例子问题分析思路解析 Prompt优化技巧Prompt优化原理 十个技巧高效优化Prompt迭代法Trick法工具法通用技巧│定基础通用技巧│做强调需求强调怎么做&#xff1f; 通用技巧│提预设Trick法│戴高帽原理 Trick法│说好话以基础计算为例: Trick法│给提示…

小红书数据分析:如何用ChatGPT输出爆文笔记

ChatGPT的热度依旧不减&#xff0c;随着技术升级&#xff0c;越来越多更高级的玩法被发掘。今天我们就来聊聊&#xff0c;如何用ChatGPT写出小红书风格的文章。 首先&#xff0c;小红书笔记制作分为两个步骤&#xff1a; 1、找选题 2、写小红书风格的笔记 我们用例子说话&a…

全国自考本科通过率仅7%,为什么还有这么多人报考?

根据教育部官网公布的《2021年全国教育事业发展统计公报》得知&#xff1a;2021年&#xff0c;全国高等教育自学考试学历教育报考625.78万人次&#xff0c;取得毕业证书48.94万人。也就是说2021年我国自考平均通过率大概在7%左右。 自考通过率为什么这么低&#xff1f; ①自考…

Android平台外部编码数据(H264/H265/AAC/PCMA/PCMU)实时预览播放技术实现

开发背景 好多开发者可能疑惑&#xff0c;外部数据实时预览播放&#xff0c;到底有什么用&#xff1f; 是的&#xff0c;一般场景是用不到的&#xff0c;我们在开发这块前几年已经开发了非常稳定的RTMP、RTSP直播播放模块&#xff0c;不过也遇到这样的场景&#xff0c;部分设…

“ChatGPT之父”勇闯币圈!数十亿人的空投计划,只需交出你的虹膜?

最近&#xff0c;Worldcoin&#xff08;世界币&#xff09;热度持续提升&#xff0c;这个由OpenAI创始人SamAltman亲自操持的加密项目&#xff0c;让沉寂已久的币圈开始躁动起来。 虽然Worldcoin并非最新项目&#xff0c;但颇具乌托邦色彩的理念&#xff0c;独特的虹膜识别机制…