关于 vue项目 中实现导入Excel表 + 预览生成的Excel

862 阅读2分钟

项目场景(需求):

1.分步骤填写数据,填写并上传业务Excel表,完成校验,并生成结果

2.生成的结果要和 业务Excel表一致,便于用户比较

3.若未填写正确,则提示用户错误信息,且重新提交

项目新建流程:

如下图所示:

2.png

业务Excel表:

如图所示:

1.png


功能实现思路:

1. 页面整体结构: 就是在index.vue里面 渲染4个不同的子路由

3.png

2. (重点)实现点击上传Excel——后端完成校验——生成预览效果

思路:

  1. 请求接口,上传文件
  2. 后端通过Python解析文件,把业务表格拆分成多个key,val值返回,如果填写的信息不符合要求,多返回一个error字段
  3. 为了生成预览的时候达到和业务表格一致的效果,因此在写HTML的时候就把结构写好
  4. 请求回来数据的时候直接v-for tr标签 渲染就可以了

代码:

上传组件:

<el-upload
      multiple
      ref="upload"
      class="upload_area"
      :auto-upload="false"
      accept=".xls,.xlsx"
      :on-change="handlePreview"
      :on-remove="handleRemove"
    >
    <el-button
      slot="trigger"
      size="small"
      type="primary"
      v-show="devfiles.length <= 0"
      >选择本地文件</el-button
    >
     <h3 slot="tip" class="el-upload__tip">
       提示:点击按钮后选择要导入的文件。
     </h3>
 </el-upload>

上传方法:

// ele上传相关 主要为了便于构造参数传给后端
handlePreview(file, fileList) {
  this.devfiles = [];
  fileList.forEach((item) => {
    this.devfiles.push(item.raw);
  });
  // console.log(this.param.devfiles);
},
handleRemove(file, fileList) {
  this.devfiles = [];
},

//上传文件核心代码
upload_file() {
      let data = new FormData();
      data.append("only_verify", 1);
      data.append("project_name", this.$bus.params.project_name);
      data.append(
        "project_create_resource",
        this.$bus.params.project_create_resource
      );
      this.devfiles.forEach((v) => {
        data.append("project_file", v);
      });
	  到这一步截止,上面都在构造一个 formdata格式的参数 data
	  用于传给后端
      
      this.$bus.upload_files.data = data
      this.$axios({
        url: this.baseUrl + "/project_create",
        headers: {
          "Content-Type": "multipart/form-data",
        },
        method: "POST",
        data,
      })
        .then((data) => {
          // console.log(data);
          let _excel = data.data.data.excel;
          this.$refs.upload.clearFiles();
          this.handleRemove();
          if (data.data.status) {
            this.$message.success("验证成功!");
          } else {
            this.$message({
              showClose: true,
              message: data.data.error_msg[0],
              type: "error",
              duration: 0,
            });
          }
		  
		  //前端控制,只有后端返回 _excel对象不为空才进行下一步
          if (_excel.contact) {
            this.next();
          }

          this.$bus.excel = _excel;
          this.$bus.upload_files.status = data.data.status
        })
    },

处理返回的josn,数据示例:

{
"base": [
        {
            "key": "单位名称",
            "value": "zzxc"
        },
        {
            "key": "需求地市",
            "value": "xxx新区"
        },
        {
            "key": "联系人",
            "value": "zxc"
        },
        {
            "key": "联系方式",
            "value": "czzcccc",
            "error": "格式不正确"
        },
        {
            "key": "客户经理",
            "value": "zc"
        },
        {
            "key": "联系方式",
            "value": "czxczxc",
            "error": "格式不正确"
        }
  ],
}

问题分析:

如图

4.png

图中第一个红框——每行只呈现 2对key-v值; 第二个红框——每行要呈现 4 对key-v值; 所以,如果直接v-for 返回的每个key-v值的话,呈现出来的表格就会和上传的不一致; 因此,需要对数据进行组装,从而达到上图的效果;


解决方案:

思路:对返回的数据进行遍历,组合成每2个一组的a 或者 每4个一组的b

a和b都是二维数组; 对于每行只呈现2对key-v值的—— 第一层遍历a,控制tr行数,第二层遍历a的元素,控制td对数; 同理,b也是如此。

lodash的chunk方法,直接使用

原生js封装的chunk方法,引入使用

代码:

1.HTML table结构

<table class="mytable">
    <thead>
      <tr>
        <th colspan="20"> 故意写大一点
          客户信息
        </th>
      </tr>
    </thead>
    <tbody>
      <template v-if="$bus.excel.contact">
        <tr  
          v-for="(v, index) in contactCustomer"
          :key="index + 'a'"
        >
        contactCustomer就是上面提到的a, 只不过这里用计算属性处理了一下
          <template v-for="(vv, ii) in v">
          	template无法加 key值,所以加在了 td上面
            <td class="td_key" :key="ii">{{ vv.key }}</td>
            <td class="td_val" :key="ii + 'b'">
              {{ vv.value }}
              <div v-if="vv.error" class="error_tip">
                {{ vv.error }}
              </div>
            </td>
          </template>
		  
		  不加这段代码,如果有7条数据,就会多出一行,不好看
		  补td空格,如果是4个一行的,下面的2变成4即可
          <template v-for="(vv, ii) in 2 - v.length">
            <td :key="ii + 'c'"></td>
            <td :key="ii + 'd'"></td>
          </template>
        </tr>
      </template>
    </tbody>
  </table>

2. js代码

import { chunk } from "lodash";
。。。。。。
computed: {
    contactCustomer() {
      return chunk(this.$bus.excel.contact.customer, 2);
    },
    contactBase() {
      return chunk(this.$bus.excel.contact.base, 4);
    },
    contactSign() {
      return chunk(this.$bus.excel.contact.sign, 3);
    },
  },

效果图:

5.png