项目场景(需求):
1.分步骤填写数据,填写并上传业务Excel表,完成校验,并生成结果
2.生成的结果要和 业务Excel表一致,便于用户比较
3.若未填写正确,则提示用户错误信息,且重新提交
项目新建流程:
如下图所示:
业务Excel表:
如图所示:
功能实现思路:
1. 页面整体结构: 就是在index.vue里面 渲染4个不同的子路由
2. (重点)实现点击上传Excel——后端完成校验——生成预览效果
思路:
- 请求接口,上传文件
- 后端通过Python解析文件,把业务表格拆分成多个key,val值返回,如果填写的信息不符合要求,多返回一个error字段
- 为了生成预览的时候达到和业务表格一致的效果,因此在写HTML的时候就把结构写好
- 请求回来数据的时候直接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": "格式不正确"
}
],
}
问题分析:
如图
图中第一个红框——每行只呈现 2对key-v值; 第二个红框——每行要呈现 4 对key-v值; 所以,如果直接v-for 返回的每个key-v值的话,呈现出来的表格就会和上传的不一致; 因此,需要对数据进行组装,从而达到上图的效果;
解决方案:
思路:对返回的数据进行遍历,组合成每2个一组的a 或者 每4个一组的b
a和b都是二维数组; 对于每行只呈现2对key-v值的—— 第一层遍历a,控制tr行数,第二层遍历a的元素,控制td对数; 同理,b也是如此。
代码:
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);
},
},