一、用法
1、动态表格(展示表格)
后端返回的值:第一个数组是表头,其余是内容
<el-table
ref="tableHeight"
:data="tableColumns"
:height="tableHeight"
border
style="width: 100%; margin-top: 1%"
@row-click="rowclick"
>
<el-table-column
v-for="(item, index) in tableData"
:key="item.label"
:prop="item.prop"
align="center"
:label="item.label"
>
<template slot-scope="scope">
{{ scope.row[index] }}
</template>
</el-table-column>
</el-table>
<el-row
ref="row"
class="block"
type="flex"
justify="end"
align="middle"
>
<el-pagination
ref="pagination"
:page-sizes="[10, 30, 50]"
:current-page.sync="page.page"
:page-size.sync="page.pagesize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-row>
<script>
import { mapGetters } from "vuex";
import {
GetHomeData,
BpmGetList,
GetFrom,
GetFromData,
AddFromData,
} from "@/api/Bpm";
export default {
name: "Process",
computed: {
...mapGetters(["userid", "name"]),
},
data() {
return {
BpmName: {}, //从常用中携带的项目信息
tableHeight: "0px", //表格高度(有切换status)
tableData: [], //表头
tableColumns: [], //表格内容
tableform: {}, //表格返回的数据之一
form: {
appid: 1, //应用编号
type: 0, //0)待办列表 1)已办列表 2)抄送 3)我发起的
keyword: "", //关键词
status: 0, //只在 我的发起时有作用 标签如下 0)草稿 1)流程中 2)已结束
},
page: {
page: 1,
pagesize: 10,
},
total: 50,
}
},
created() {
this.BpmGetList(this.form);
},
methods: {
// 获取列表
BpmGetList(form) {
const a = JSON.parse(localStorage.getItem("Goprocess"));
this.BpmName = a;
this.form.appid = this.BpmName.id;
BpmGetList({
...this.page,
...form,
userid: this.userid,
}).then((res) => {
this.tableform = res.data;
this.total = res.data.total;
// console.log(this.tableform, "列表");
if (res.data.table) {
// 表头
this.tableData = res.data.table[0].map((i, j) => {
return {
label: i,
prop: "a" + [j],
};
});
this.tableColumns = res.data.table.filter(function (
item,
index,
arr
) {
return index != 0;
});
}
});
},
}
}
</script>
2、动态表格(可编辑)
后端返回的结构:第一个数组是表头,第二个是每个单元格对应的组件
我的这个动态表格是放在动态表单中的,所以一开始是没有数据的,需要点击添加行后,出现对应组件,然后进行填写数据,其中点击选择按钮后,还会出现一个表格进行填写,这个弹窗里的表格是固定的。
至于表格数据回显这一块我这暂时不需要,所以就没有做。
如果你觉得不太清晰,你可以看我的另一篇【el】表单,这里面有关于动态表单的完整代码可以查看。
我这里就只写主要代码了
<template>
<div id="SearchHead">
<el-form-item v-if="item.type == 7" :label="item.name">
<el-button size="small" @click="addtable(item)" class="addbtn"
>添加行</el-button
>
<el-button size="small" @click="deletetable(item)" class="Cancelbtn"
>删除</el-button
>
<el-table
ref="table"
:data="item.table1"
border
style="width: 100%; margin-top: 1%"
:header-cell-style="{
padding: '0',
}"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="45" align="center">
</el-table-column>
<el-table-column
type="index"
label="序号"
width="50"
align="center"
>
</el-table-column>
<el-table-column
v-for="(i, index) in item.table"
:key="i.label"
:prop="i.prop"
align="center"
:label="i.label"
>
<template slot-scope="scope">
<!-- <div v-if="scope.row[index] instanceof Object ? true : false"> -->
<el-input
size="small"
v-if="scope.row[index].type === 0"
v-model="scope.row[index].default_val"
placeholder="请输入"
></el-input>
<el-input-number
size="small"
v-if="scope.row[index].type === 1"
v-model="scope.row[index].default_val"
placeholder="请输入"
></el-input-number>
<el-select
size="small"
v-if="scope.row[index].type === 2"
v-model="scope.row[index].default_val"
placeholder="请选择"
>
<el-option
v-for="(i, ind) in scope.row[index].attr"
:key="ind"
:label="i"
:value="i"
>
</el-option>
</el-select>
<el-date-picker
size="small"
v-if="scope.row[index].type === 3"
v-model="scope.row[index].default_val"
type="date"
placeholder="选择日期"
format="yyyy-MM-dd"
>
</el-date-picker>
<el-date-picker
size="small"
v-if="scope.row[index].type === 4"
v-model="scope.row[index].default_val"
type="datetime"
placeholder="选择日期时间"
>
</el-date-picker>
<el-radio-group
v-if="scope.row[index].type === 5"
v-model="scope.row[index].default_val"
>
<el-radio
:label="ii"
v-for="ii in scope.row[index].attr"
:key="ii"
>{{ ii }}</el-radio
>
</el-radio-group>
<el-checkbox-group
v-if="scope.row[index].type === 6"
v-model="scope.row[index].default_val"
>
<el-checkbox
:label="jj"
v-for="jj in scope.row[index].attr"
:key="jj"
></el-checkbox>
</el-checkbox-group>
<el-upload
v-if="scope.row[index].type === 8"
action="#"
:class="{
hide: scope.row[index].attr.length === 1 ? true : false,
}"
name="file_name"
:http-request="
(file, fileList) =>
http(file, fileList, scope.row, 'wenjian', index)
"
:limit="1"
:show-file-list="true"
:file-list="scope.row[index].attr"
:on-change="
(file, fileList) =>
handlechange(
file,
fileList,
scope.row,
'wenjian',
index
)
"
:on-remove="
(file, fileList) =>
Remove(file, fileList, scope.row, 'wenjian', index)
"
>
<el-button
:class="{
hide: scope.row[index].attr.length === 1 ? true : false,
}"
icon="el-icon-upload2"
style="width: 100%; text-align: left"
size="small"
class="dashedbtn"
>上传文件</el-button
>
</el-upload>
<el-select
size="small"
filterable
v-if="scope.row[index].type === 9"
v-model="scope.row[index].default_val"
placeholder="请选择"
>
<el-option
v-for="(i, ind) in scope.row[index].attr"
:key="ind"
:label="i.name"
:value="i.name"
>
</el-option>
</el-select>
<el-popover
append-to-body
ref="editPopover"
placement="right-end"
width="750"
trigger="manual"
v-model="scope.row[index].show"
v-if="scope.row[index].type === 10"
:reference="prevTarget"
:key="popperFlag"
>
<div>
<el-button
size="small"
class="addbtn"
@click="add(scope.row[index])"
>添加行</el-button
>
<el-button
size="small"
class="addbtn"
@click="sub(scope.row[index])"
>保存</el-button
>
<el-button
size="small"
class="addbtn"
@click="cancel(scope.row[index])"
>取消</el-button
>
</div>
<el-table
border
height="45vh"
style="width: 100%; margin-top: 10px"
:data="scope.row[index].attr"
>
<el-table-column
align="center"
property="date"
label="检测标准"
>
<template slot-scope="sco">
<el-select
style="width: 100%"
filterable
v-model="sco.row.standard"
multiple
placeholder="请选择"
@change="changeStandard"
value-key="id"
>
<el-option
v-for="item in standardoptions"
:key="item.value"
:label="item.no"
:value="item"
>
</el-option>
</el-select>
</template>
</el-table-column>
<el-table-column
align="center"
property="name"
label="检测项目"
>
<template slot-scope="sco">
<el-select
style="width: 100%"
filterable
v-model="sco.row.item"
multiple
placeholder="请选择"
@focus="onfocus(sco.row)"
>
<el-option
v-for="item in itemoptions"
:key="item.id"
:label="
item.name + '(' + item.projecttypename + ')'
"
:value="
item.name + '(' + item.projecttypename + ')'
"
>
</el-option>
</el-select>
</template>
</el-table-column>
<el-table-column
width="60"
property="name"
label="操作"
align="center"
>
<template slot-scope="sco">
<el-button
type="text"
@click="del(scope.row[index].attr, sco.$index)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<el-button
type="text"
slot="reference"
@click="showPopover(scope.row[index], $event)"
>选择</el-button
>
</el-popover>
<!-- </div>
<div v-else>
<el-input
size="small"
v-model="scope.row[index]"
placeholder="请输入"
></el-input>
</div> -->
</template>
</el-table-column>
</el-table>
</el-form-item>
</div>
</template>
<script>
import axios from "axios";
import { UploadData } from "@/api/Equipment";
import { mapGetters } from "vuex";
import { GetParameterListById, GetAllStandardList } from "@/api/Basic";
export default {
name: "SearchHead",
computed: {
...mapGetters(["userid", "name", "btnsUrl", "token"]),
},
props: {
List: [Object, Array],
},
data() {
return {
multipleSelection: [], //多选
tableFormrules: [],
tableForm: {},
ta: [],
fileList: [], //文件列表
formData: new FormData(),
up: [],
url: "", //项目类别的地址
standardoptions: [], //检测标准的列表
itemoptions: [], //检测项目的列表
ids: "", //检测标准id的集合
tablevisible: false, //检测标准和项目的弹出框
prevTarget: null, // 编辑 Popover 的 Reference (参照),用于 popover.js 对齐两个元素
popperFlag: false, // 用于编辑 Popover 的刷新
};
},
mounted() {
// 表格中的产品名称的数据(因为是根据后端返回的地址进行调用接口的,就是第一张图events中的地址))
this.List.dom.forEach((i, j) => {
if (i.type === 7) {
// 工装夹具
if (i.attr[1].length > 0) {
i.attr[1].forEach((ele) => {
// 下拉框(项目类别)
if (ele.type === 9) {
if (ele.events[0].command.substr(0, 10) == "{{st_url}}") {
this.btnsUrl.map((obj) => {
if (obj.key === "{{st_url}}") {
this.url = ele.events[0].command.replace(
/{{st_url}}/,
obj.value
);
axios({
method: "get",
url: this.url,
// params: {
// name: this.names,
// },
headers: {
token: this.token,
},
}).then((res) => {
ele.attr = res.data.data;
});
} else {
//这里还没做处理,但是和上面是一致的
this.url = ele.events[0].command.replace(
/{{url}}/,
obj.value
);
}
});
}
}
});
}
}
});
// 弹窗中,检测标准,第一个下拉框的接口
GetAllStandardList().then((res) => {
this.standardoptions = res.data;
});
},
created() {},
methods: {
// 表格添加行====================================
addtable(item) {
var a = [];
a = item.attr[1].map((obj, idx) => {
return {
name: "",
sort: obj.sort,
type: obj.type,
required: obj.required,
default_val: obj.default_val,
attr: obj.type === 10 ? [] : obj.attr,
};
});
item.table1.push(a);
// // 判断表格最后一行是否都填完整
// if (this.table1.length > 0) {
// this.table1[this.table1.length - 1].forEach((item) => {
// if (item === "") {
// ar = true;
// } else {
// ar = false;
// }
// });
// if (ar) {
// this.$message.error("请将表格填写完整");
// } else {
// this.table1.push(lis);
// }
// } else {
// this.table1.push(lis);
// }
},
// 表格删除
deletetable(item) {
var da = [];
da = item.table1.filter((itemA) => {
return this.multipleSelection.every((itemB) => {
return itemB !== itemA;
});
});
item.table1 = da;
this.multipleSelection = [];
},
toggleSelection(rows) {
if (rows) {
rows.forEach((row) => {
this.$refs.table.toggleRowSelection(row);
});
} else {
this.$refs.table.clearSelection();
}
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
// 表格中的导入=====================================
handlechange(file, fileList, row, col, index) {
row[index].attr = fileList;
},
Remove(file, fileList, row, col, index) {
row[index].attr = [];
},
async http(file, fileList, row, col, index) {
var formData = new FormData();
formData.append("files", file.file);
const res = await UploadData(formData);
if (res.code === 200) {
row[index].default_val = res.data[0].FileUrl;
this.$mess.success("上传成功"); //这个是封装的,无论调用多少次,都只显示一次
}
},
// 检测标准和检测项目======================
showPopover(row, e) {
//阻止事件冒泡,兼容ie
if (event.stopPropagation) {
event.stopPropagation();
} else if (window.event) {
window.event.cancelBubble = true;
}
let currentTarget = e.target; // 赋值当前点击的编辑
// 判断是否需要切换
if (this.prevTarget === currentTarget) {
// 同一个元素重复点击
row.show = !row.show;
} else {
// 切换不同元素, 判断之前是否有点击其他编辑 prevTarget
if (this.prevTarget) {
// 先清除之前的编辑框
this.clearEditPopperComponent(row);
// 然后生成新的编辑框
this.$nextTick(() => {
this.prevTarget = currentTarget;
row.show = true;
});
} else {
// 首次
// console.log("首次--->this.prevTarget");
this.prevTarget = currentTarget;
row.show = true;
}
}
},
// 清空编辑组件
clearEditPopperComponent(row) {
this.prevTarget = null;
this.popperFlag = !this.popperFlag;
row.show = false;
},
//弹窗中处理第一个下拉框的值,传给后端的是name,但是第二下拉框的接口需要第一个下拉框的id集合
changeStandard(val) {
this.ids = [];
const arr = val.map((i) => {
return i.id;
});
this.ids = arr.toString(",");
},
//弹窗中第二个下拉框必须是第一个下拉框有值才能调用接口获取数据
onfocus(row) {
if (row.standard.length > 0) {
GetParameterListById({ standardid: this.ids }).then((res) => {
this.itemoptions = res.data;
});
}
},
//弹窗中的添加行
add(i, index) {
// console.log(i);
const ar = {
standard: [],
item: [],
show: false,
};
i.attr.push(ar);
},
//弹窗中的删除
del(i, index) {
i.splice(index, 1);
},
//弹窗中的保存
sub(obj) {
var nos = [];
obj.default_val = obj.attr.map((i) => {
nos = i.standard.map((obj) => {
return obj.no;
});
return {
standard: nos,
item: i.item,
};
});
obj.show = !obj.show;
},
//弹窗中的取消
cancel(obj) {
obj.attr.splice(
obj.default_val.length,
obj.attr.length - obj.default_val.length
);
obj.show = !obj.show;
},
},
};
</script>
<style lang="scss">
#SearchHead {
width: 100%;
.el-form-item {
width: 100%;
}
.el-form-item__content {
width: 100%;
}
.el-select {
width: 100%;
}
.el-textarea__inner {
border: 1px solid #dcdfe6 !important;
}
.el-date-editor.el-input {
width: 100%;
}
.el-upload {
width: 100%;
}
.upload {
.el-upload-list {
text-align: left !important;
}
}
.hide .el-upload--text {
display: none !important;
}
.el-table__body-wrapper {
overflow-y: scroll;
}
}
</style>
3、动态表格(合并列,可编辑)
逻辑顺序:表单数据添加——添加行——选择检测标准——检测项目——产品名称的调用——添加——确定
由于这个表格是固定的,所以我这里的基本数据就是固定的,只不过展现形式还是根据动态的来,和上面的表格一样
在添加行的时候判断,上面表单中的某些选项是否已经选择,只有选择了之后才可以添加;
出现弹窗后,先调用接口获取检测标准的数据后,进行选择标准,然后再调用接口获取项目的数据,项目选择后再调用产品名称的接口,最后点击添加
完整代码看我的另一篇【el】表单,我这里就写主要代码了
rowspan方法:第一行数据直接添加,从第二行数据开始,进行和前一个数据比较,判断和否和前一个数据的序号相同,相同则为0,不相同则为1
objectSpanMethod方法:指定合并那些列和行
<template>
<el-form-item v-if="item.type == 11" :label="item.name">
<el-button size="small" @click="ad(item)" class="addbtn"
>添加行</el-button
>
<el-button size="small" @click="dele(item)" class="Cancelbtn"
>删除</el-button
>
<el-table
:ref="'table' + index"
:data="item.table1"
border
:span-method="objectSpanMethod"
style="width: 100%; margin-top: 1%"
:header-cell-style="{
padding: '0',
}"
@selection-change="handle"
>
<el-table-column type="selection" width="45" align="center">
</el-table-column>
<el-table-column
v-for="i in item.table"
:key="i.label"
:prop="i.prop"
align="center"
:label="i.label"
>
<template slot-scope="scope">
{{ scope.row[i.prop] }}
</template>
</el-table-column>
<el-table-column
type="index"
label="操作"
width="120"
align="center"
>
<template slot-scope="scope">
<el-button
size="small"
@click="edit(scope.row, scope.$index, item)"
class="addbtn"
>编辑</el-button
>
</template>
</el-table-column>
</el-table>
</el-form-item>
<!-- 添加行的弹窗 -->
<el-dialog
:append-to-body="true"
:title="title"
:visible.sync="dialogVisible"
width="80%"
@close="closetable"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<el-form
:inline="true"
:model="ruleForm"
ref="dynamicValidateForm"
label-width="100px"
class="demo-dynamic"
>
<el-form-item label="检测标准" prop="jcbz">
<el-select
v-model="ruleForm.jcbz"
placeholder="请选择检测标准"
filterable
value-key="id"
@change="Standard"
>
<el-option
v-for="item in standardoptions"
:key="item.id"
:label="item.no"
:value="item"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="检测项目" prop="jcxm">
<el-select
v-model="ruleForm.jcxm"
placeholder="请选择检测项目"
filterable
value-key="id"
@focus="focus()"
@change="jcxm"
>
<el-option
v-for="item in itemoptions"
:key="item.id"
:label="item.name"
:value="item"
>
</el-option>
</el-select>
</el-form-item>
</el-form>
<el-button size="small" @click="diaAdd()" class="addbtn">添加</el-button>
<el-button size="small" @click="diaDele()" class="Cancelbtn"
>删除</el-button
>
<el-table
:data="all1"
style="width: 100%; margin-top: 10px"
border
@selection-change="diaHandle"
>
<el-table-column type="selection" width="45" align="center">
</el-table-column>
<el-table-column
v-for="(i, index) in all"
:key="i.label"
:prop="i.prop"
align="center"
:label="i.label"
>
<template slot-scope="scope">
<el-input
size="small"
v-if="scope.row[index].type === 0"
v-model="scope.row[index].default_val"
placeholder="请输入"
></el-input>
<el-input-number
size="small"
v-if="scope.row[index].type === 1"
v-model="scope.row[index].default_val"
placeholder="请输入"
></el-input-number>
<el-date-picker
size="small"
v-if="scope.row[index].type === 3"
v-model="scope.row[index].default_val"
type="date"
placeholder="选择日期"
format="yyyy-MM-dd"
>
</el-date-picker>
<el-date-picker
size="small"
v-if="scope.row[index].type === 4"
v-model="scope.row[index].default_val"
type="datetime"
placeholder="选择日期时间"
>
</el-date-picker>
<el-select
size="small"
filterable
v-if="scope.row[index].type === 9"
v-model="scope.row[index].default_val"
placeholder="请选择"
>
<el-option
v-for="(i, ind) in scope.row[index].attr"
:key="ind"
:label="i.name"
:value="i.name"
>
</el-option>
</el-select>
</template>
</el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button @click="closetable()">取 消</el-button>
<el-button type="primary" @click="sure()">确 定</el-button>
</span>
</el-dialog>
</template>
<script>
import axios from "axios";
import { mapGetters } from "vuex";
import {
GetTypeListById,
GetParameterListById,
GetAllStandardList,
GetStandardListById,
} from "@/api/Basic";
import { Time } from "@/utils/index";
export default {
name: "SearchHead",
computed: {
...mapGetters(["userid", "name", "btnsUrl", "token"]),
},
props: {
List: [Object, Array],
},
data() {
return {
multipleSelection: [], //多选
tableFormrules: [],
tableForm: {},
standardoptions: [], //检测标准的列表
itemoptions: [], //检测项目的列表
ids: "", //检测标准id的集合
ite: {}, //产品大类的选择
it: "", //资质
ie: "", //参数
im: [], //产品名称(产品类别)
all: [],
all1: [],
dialogVisible: false,
arr: {}, //弹窗所需的当前表格信息
ruleForm: { jcbz: "", jcxm: "" },
spanArr: [],
position: 0,
editnum: 1,
row: {},
multiple: [],
title: "新增",
};
},
watch: {
List: {
handler(newVal, oldVal) {
if (JSON.stringify(newVal) !== "{}") {
this.ne();//处理数据
}
},
immediate: true, // //immediate:true代表如果在 wacth 里声明了之后,就会立即先去执行里面的handler方法,如果为 false,不会在绑定的时候就执行。
// deep: true, //默认值是 false,代表是否深度监听
},
},
methods: {
// 新测试明细=================================
ne() {
this.List.dom.forEach((i, j) => {
if (i.type === 11) {
this.all1 = [
// 需要的类型
// [
// {
// sort: 45,
// type: 0,
// name: "产品名称",
// attr: [],
// required: false,
// default_val: "1",
// events: [],
// },
// {
// sort: 46,
// type: 0,
// name: "商标",
// attr: [],
// required: false,
// default_val: "",
// events: [],
// },
// {
// sort: 47,
// type: 0,
// name: "型号规格",
// attr: [],
// required: false,
// default_val: "",
// events: [],
// },
// ],
];
this.all = [
{ label: "产品名称", prop: "a3" },
{ label: "商标", prop: "a4" },
{ label: "型号规格", prop: "a5" },
{ label: "产品编号/批号", prop: "a6" },
{ label: "生产日期", prop: "a7" },
{ label: "数量", prop: "a8" },
{ label: "备注", prop: "a9" },
];
i.table = [
{ label: "序号", prop: "a0" },
{ label: "检测标准", prop: "a1" },
{ label: "检测项目", prop: "a2" },
{ label: "产品名称", prop: "a3" },
{ label: "商标", prop: "a4" },
{ label: "型号规格", prop: "a5" },
{ label: "产品编号/批号", prop: "a6" },
{ label: "生产日期", prop: "a7" },
{ label: "数量", prop: "a8" },
{ label: "备注", prop: "a9" },
];
i.attr = [
[
"编号",
"检测标准",
"检测项目",
"产品名称",
"商标",
"型号规格",
"产品编号/批号",
"生产日期",
"数量",
"备注",
],
[
{
sort: 42,
type: 0,
name: "编号",
attr: [],
required: false,
default_val: "",
events: [],
},
{
sort: 43,
type: 9,
name: "检测标准",
attr: [],
required: false,
default_val: "",
events: [],
},
{
sort: 44,
type: 9,
name: "检测项目",
attr: [],
required: false,
default_val: "",
events: [],
},
{
sort: 45,
type: 9,
name: "产品名称",
attr: [],
required: false,
default_val: "",
events: [],
},
{
sort: 46,
type: 0,
name: "商标",
attr: [],
required: false,
default_val: "",
events: [],
},
{
sort: 47,
type: 0,
name: "型号规格",
attr: [],
required: false,
default_val: "",
events: [],
},
{
sort: 48,
type: 0,
name: "产品编号/批号",
attr: [],
required: false,
default_val: "",
events: [],
},
{
sort: 49,
type: 3,
name: "生产日期",
attr: [],
required: false,
default_val: "",
events: [],
},
{
sort: 50,
type: 1,
name: "数量",
attr: [],
required: false,
default_val: "",
events: [],
},
{
sort: 51,
type: 0,
name: "备注",
attr: [],
required: false,
default_val: "",
events: [],
},
],
];
i.table1 = [
//需要的形式
// {
// a0: "1",
// a1: "YY/T 0520-2009 5.2",
// a2: "尺寸",
// a3: "个性化基台及螺钉1",
// a4: "N/A",
// a5: "三边形ANT-R",
// a6: "QY2205034",
// a7: "2022.05.14",
// a8: 5,
// a9: "备注",
// },
];
// 有没有默认值
if (i.default_val.length > 0) {
i.default_val.forEach((item, index) => {
item.cpmc.forEach((n) => {
i.table1.push({
a0: item.no,
a1: item.jcbz,
a2: item.jcxm,
a3: n.cpmc,
a4: n.sb,
a5: n.ggxh,
a6: n.cpbhph,
a7: n.scrq,
a8: n.sl,
a9: n.bz,
});
});
});
}
for (let index = 0; index < i.table1.length; index++) {
this.rowspan(i.table1);
}
}
});
},
rowspan(tableData, spanArr, position, spanName) {
// 每次调用清空数据
this.spanArr = [];
this.position = 0;
tableData.forEach((item, index) => {
if (index === 0) {
this.spanArr.push(1);
this.position = 0;
} else {
// 为需要合并查询的项
if (tableData[index].a0 === tableData[index - 1].a0) {
this.spanArr[this.position] += 1;
this.spanArr.push(0);
} else {
this.spanArr.push(1);
this.position = index;
}
}
});
},
//合并行列
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (
columnIndex === 0 ||
columnIndex === 1 ||
columnIndex === 2 ||
columnIndex === 3 ||
columnIndex === 11
) {
const _row = this.spanArr[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col,
};
}
},
edit(row, index, item) {
this.arr = [];
this.row = {};
this.title = "编辑";
this.arr = item; //赋值给this.arr,不能使用json,不然编辑保存的时候没有用
this.row = JSON.parse(JSON.stringify(row));
this.editnum = 1;
const at = JSON.parse(JSON.stringify(item.table1)).filter((i) => {
if (i.a0 === row.a0) {
return i;
}
});
this.ruleForm.jcbz = at[0]["a1"];
this.ruleForm.jcxm = at[0]["a2"];
// 删除前三个数据
at.forEach((j) => {
delete j.a0;
delete j.a1;
delete j.a2;
});
this.all1 = at;
const ii = JSON.parse(JSON.stringify(item.table));
const jj = JSON.parse(JSON.stringify(item.attr[1]));
ii.splice(0, 3);
jj.splice(0, 3);
let ab = [];
this.all1.filter((ele, ij) => {
let bt = [];
bt = jj.map((obj, index) => {
return {
name: "",
sort: obj.sort,
type: obj.type,
required: obj.required,
default_val: ele["a" + (index + 3)],
attr: obj.type === 10 ? [] : obj.attr,
};
});
ab.push(bt);
});
this.all = ii;
this.all1 = ab;
this.dialogVisible = true;
},
ad(item) {
// 判断产品大类和报告用章类型是否为空
let pro = {};
let baogao = {};
this.List.dom.forEach((i, j) => {
if (i.name === "产品大类") {
pro = i;
} else if (i.name === "报告用章类型") {
baogao = i;
}
});
if (pro.default_val === "") {
this.$message.error("请先填写表单中的产品大类和报告用章类型");
} else if (baogao.default_val === "") {
this.$message.error("请先填写表单中的产品大类和报告用章类型");
} else {
// 获取产品大类对应的id
this.ite = pro.attr.find((obj) => {
return obj.name === pro.default_val;
});
const abc = baogao.default_val.filter((ele) => {
return ele !== "无";
});
if (abc.length === 0) {
this.it = "";
} else {
this.it = abc.join(",");
}
GetStandardListById({
productlineid: this.ite.id,
qualifications: this.it,
}).then((res) => {
// console.log(res);
this.standardoptions = res.data;
});
this.arr = [];
this.all1 = [];
this.title = "新增";
this.editnum = 0;
this.dialogVisible = true;
this.arr = item;
}
},
dele(item) {
var da = [];
da = item.table1.filter((itemA) => {
return this.multipleSelection.every((itemB) => {
// console.log(itemB);
return itemB.a0 !== itemA.a0;
});
});
item.table1 = da;
this.multipleSelection = [];
this.$forceUpdate(); //这个是给二级表单用的,二级表单如果不加这个,则数据更新了但是视图没变;而发起新的弹窗则不会出现这个问题,不知道是不是组件嵌套的问题
},
handle(val) {
this.multipleSelection = val;
},
// 新测试明细弹窗中的表格操作=================================
closetable() {
this.ruleForm = { jcbz: "", jcxm: "" };
this.all1 = [];
this.dialogVisible = false;
},
Standard(val) {
this.ids = val.id;
this.ruleForm.jcxm = "";
this.ie = "";
// this.ids = [];
// const arr = val.map((i) => {
// return i.id;
// });
// this.ids = arr.toString(",");
},
focus() {
// if (this.ids.length > 0) {
// console.log(this.ids);
GetParameterListById({
standardid: this.ids,
qualifications: this.it,
}).then((res) => {
// console.log(res);
this.itemoptions = res.data;
});
// }
},
async jcxm(val) {
// console.log(val, "jcxm");
this.ie = val.id;
// 检测项目选完后调用接口获取产品名称
const re = await GetTypeListById({
standardid: this.ids,
parameterid: this.ie,
});
this.im = re.data;
},
sure() {
const b = this.arr.table.map((obj, idx) => {
return obj.prop;
});
// console.log(this.ruleForm);
// 添加
if (this.editnum === 0) {
// 序号
let num = 0;
if (this.arr.table1.length > 0) {
num = Number(this.arr.table1[this.arr.table1.length - 1].a0) + 1;
} else {
num = 1;
}
var aa = [];
this.all1.forEach((item, index) => {
var a = {};
this.$set(a, b[0], String(num));
this.$set(a, b[1], this.ruleForm.jcbz.no);
this.$set(a, b[2], this.ruleForm.jcxm.name);
for (let index = 0; index < item.length; index++) {
this.$set(a, b[index + 3], item[index].default_val);
}
aa.push(a);
});
this.arr.table1.push(...aa);
this.rowspan(this.arr.table1);
this.dialogVisible = false;
} else {
// 编辑
// 序号
const num = this.row.a0;
var aa = [];
this.all1.forEach((item, index) => {
var a = {};
this.$set(a, b[0], num);
this.$set(a, b[1], this.ruleForm.jcbz.no);
this.$set(a, b[2], this.ruleForm.jcxm.name);
for (let index = 0; index < item.length; index++) {
this.$set(a, b[index + 3], item[index].default_val);
}
aa.push(a);
});
// 获取第一个符合条件的下标
const findIndex = this.arr.table1.findIndex(
(item) => item.a0 === aa[0].a0
);
// 获取所有符合条件的长度
let nu = 0;
this.arr.table1.forEach((re, ind) => {
if (re.a0 === aa[0].a0) {
nu += 1;
}
});
// 进行替换
this.arr.table1.splice(findIndex, nu, ...aa);
this.rowspan(this.arr.table1);
this.dialogVisible = false;
}
},
async diaAdd() {
if (this.ruleForm.jcbz !== "" && this.ruleForm.jcxm !== "") {
let newar = [];
newar = JSON.parse(JSON.stringify(this.arr.attr[1]));
if (this.im.length > 0) {
var a = [];
newar.splice(0, 3);
a = newar.map((obj, idx) => {
return {
name: "",
sort: obj.sort,
type: obj.type,
required: obj.required,
default_val: obj.default_val,
attr: obj.type === 11 ? [] : obj.attr,
};
});
a[0].attr = this.im; //赋值给产品名称
this.all1.push(a);
} else {
this.$message.error("暂无产品名称,请到基础库添加相关信息");
}
} else {
this.$message.error("请先选择检测标准和检测项目");
}
},
diaDele() {
var da = [];
da = this.all1.filter((itemA) => {
return this.multiple.every((itemB) => {
return itemB !== itemA;
});
});
this.all1 = da;
this.multipleSelection = [];
this.$forceUpdate(); //这个是给二级表单用的,二级表单如果不加这个,则数据更新了但是视图没变;而发起新的弹窗则不会出现这个问题,不知道是不是组件嵌套的问题
},
diaHandle(val) {
this.multiple = val;
},
},
};
</script>
4、动态表格(合并单元格后多选)
1、选择的就是一整个合并后的内容,不是单行
2、我这里是放在tabs中的,所以我在select事件中多传递了一个参数item,当前标签页的数据
<el-tabs v-model="active" @tab-click="handleClick">
<el-tab-pane
v-for="item in editableTabs"
:key="item.name"
:label="item.title"
:name="item.name"
>
<div>
<el-button
v-if="active === '1'"
size="small"
@click="addgroup(item)"
class="addbtn"
>确认分组</el-button
>
<el-button
v-if="active !== '1'"
size="small"
@click="elegroup(item)"
class="addbtn"
>取消分组</el-button
>
</div>
<el-table
ref="multipleTableDevice"
:data="item.ceshiData"
:span-method="objectSpanMethod"
border
style="margin-top: 10px"
@select="
(selection, row) => {
selectTab(selection, row, item);
}
"
@select-all="selectAll"
>
<el-table-column type="selection" width="45" align="center">
</el-table-column>
<el-table-column
prop="a0"
label="序号"
width="50"
align="center"
>
</el-table-column>
<el-table-column prop="a1" label="产品名称" align="center">
</el-table-column>
<el-table-column prop="a2" label="商标" align="center">
</el-table-column>
<el-table-column prop="a3" label="型号规格" align="center">
</el-table-column>
<el-table-column prop="a4" label="产品编号/批号" align="center">
</el-table-column>
<el-table-column prop="a5" label="生产日期" align="center">
</el-table-column>
<el-table-column prop="a6" label="数量" align="center">
</el-table-column>
<el-table-column prop="a7" label="备注" align="center">
</el-table-column>
<el-table-column prop="a8" label="产品大类" align="center">
</el-table-column>
<el-table-column prop="a9" label="产品类型" align="center">
</el-table-column>
<el-table-column prop="a10" label="检测标准" align="center">
</el-table-column>
<el-table-column prop="a11" label="检测项目" align="center">
</el-table-column>
<el-table-column
v-if="active === '1'"
type="index"
label="操作"
width="50"
align="center"
>
<template slot-scope="scope">
<el-button
type="text"
size="small"
@click="ele(item, scope.row, scope.$index)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
<script>
export default {
data() {
return {
spanArr: [], // 存合并行数据的数组
position: 0, // 合并行数据数组下标
rowIndex: 1, // 序号
multiple: [],
activeName: "first",
active: "1",
ceshimultiple: [],
ceshidialog: false,
editableTabs: [
{
title: "待分组", //分页名称
name: "1", //分页序号,一定是字符串形式 1、2、3、4
ceshiData: [], //分页数组
},
],
};
},
methods: {
// 表格序号需要一起合并的(添加新数据的时候,如果表格上合并处的数据和新添加的数据一致,
//则需要添加在相同出的后面,这时序号不能递增)
rowspan(tableData, spanArr, position, spanName) {
// 每次调用清空数据
this.spanArr = [];
this.position = 0;
this.rowIndex = 1;
tableData.forEach((item, index) => {
if (index === 0) {
this.spanArr.push(1);
this.position = 0;
tableData[index].a0 = this.rowIndex; //给表格的第一个序号是固定的
this.rowIndex++;
} else {
// 为需要合并查询的项
if (
tableData[index].qdxh === tableData[index - 1].qdxh
) {
this.spanArr[this.position] += 1;
this.spanArr.push(0);
} else {
this.spanArr.push(1);
this.position = index;
tableData[index].a0 = this.rowIndex; //给表格的第一个序号是固定的
this.rowIndex++;
}
}
});
},
// 表格序号不需要合并的(数据不相同,则序号递增)
rowspanIndex(tableData, spanArr, position, spanName) {
// 每次调用清空数据
this.spanArr = [];
this.position = 0;
tableData.forEach((item, index) => {
if (index === 0) {
this.spanArr.push(1);
this.position = 0;
} else {
// 为需要合并查询的项
if (
tableData[index].qdxh === tableData[index - 1].qdxh
) {
this.spanArr[this.position] += 1;
this.spanArr.push(0);
} else {
this.spanArr.push(1);
this.position = index;
}
}
});
},
//合并行列
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (
columnIndex === 0 ||
columnIndex === 1 ||
columnIndex === 2 ||
columnIndex === 3 ||
columnIndex === 4 ||
columnIndex === 5 ||
columnIndex === 6 ||
columnIndex === 7
) {
const _row = this.spanArr[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col,
};
}
},
//选中
selectTab(selection, row, item) {
let newArr = [];
let isSelect = null;
//true是选中,0是取消选中
isSelect = selection.length && selection.indexOf(row) > -1;
//获取对应所有合并项的数组
item.ceshiData.forEach((i) => {
if (row.qdxh === i.qdxh) {
newArr.push(i);
}
});
if (isSelect === true) {
this.ceshimultiple.push(...newArr);
//反选,全选中,则全选也需要打钩
if (
this.ceshimultiple.length === this.editableTabs[0].ceshiData.length
) {
this.editableTabs[0].ceshiData.forEach((row) => {
this.$refs.multiple[Number(item.name - 1)].toggleRowSelection(
row,
true
);
});
}
} else {
let arr3 = this.ceshimultiple.filter((item) => {
return newArr.every((item2) => {
return item.qdxh != item2.qdxh;
});
});
this.ceshimultiple = arr3;
//反选,全都不选,则全选也取消选中
if (this.ceshimultiple.length === 0) {
this.editableTabs[0].ceshiData.forEach((row) => {
this.$refs.multiple[Number(item.name - 1)].toggleRowSelection(
row,
false
);
});
}
}
},
// 全选选中的数据
selectAll(val) {
this.ceshimultiple = val;
},
handleClick(tab, event) {
this.ceshimultiple = [];
this.rowspan(this.editableTabs[Number(tab.name) - 1].ceshiData);
},
}
};
</script>
5、调用后端接口进行表格排序,点击分页不再是当前页排序
将sortable设置为custom、在 Table 上监听sort-change事件,在事件回调中可以获取当前排序的字段名和排序顺序、并且通过default-sort属性设置默认的排序列和排序顺序。
<template>
<el-table
:data="FieldRecordData"
:default-sort="{ prop: 'date' }"
@sort-change="sortchange"
>
<el-table-column
prop="date"
sortable="custom"
label="填报日期"
align="center"
>
<template slot-scope="scope">
{{ scope.row.date | formatDate }}
</template>
</el-table-column>
</el-table>
<el-row class="block" type="flex" justify="end" align="middle">
<el-pagination
:current-page="page.page"
:page-size.sync="page.pagesize"
:page-sizes="[10, 20, 30, 40]"
layout="total, sizes, prev, pager, next, jumper"
:total="page.total"
:pager-count="5"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-row>
</template>
<script>
import { getRecordsList } from '@/api/FieldRecord'
export default {
data () {
return {
FieldRecordData: [], // 列表数据(展示的数据)
num: 0,//正序
page: {
pagesize: 10,
page: 1,
total: 50
},
}
},
created () {
this.getlist(0, this.page.page, this.page.pagesize)
},
methods: {
// 排序
async sortchange (column, prop, order) {
// 降序
if (column.order === 'descending') {
this.getlist(1, this.page.page, this.page.pagesize)
this.num = 1
} else if (column.order === 'ascending') {
this.getlist(0, this.page.page, this.page.pagesize)
this.num = 0
} else {
this.getlist(0, this.page.page, this.page.pagesize)
this.num = 0
}
},
// 获取数据
async getlist (num, page, pagesize) {
const id = this.$route.params.id
this.loading = true
const res = await getRecordsList({ page: page, pagesize: pagesize, projectid: id, order: num })
this.FieldRecordData = res.data.records
this.page.total = res.data.total
this.loading = false
},
// 分页
handleSizeChange (Sizechange) {
this.page.pagesize = Sizechange
this.getlist(this.num, this.page.page, this.page.pagesize)
},
handleCurrentChange (val) {
this.page.page = val
this.getlist(this.num, this.page.page, this.page.pagesize)
}
}
}
</script>
6、表格的序号为连续
表格使用分页,第一页的序号是1-5,第二页则是6-10,不再从头开始
<el-table-column :index="CljcMethod" type="index" label="序号" width="50" align="center" >
</el-table-column>
methods: {
//this.Cljcpage.page是页码,this.Cljcpage.pagesize是一页显示条数
CljcMethod (index) { return (index + 1) + (this.Cljcpage.page - 1) * this.Cljcpage.pagesize; },
}
7、表格中可编辑的日期选择器设置使用范围
因为是在表格中的选择器,还要进行新增编辑,所以这里的picker-options都定义了两个,一个在data中,一个在methods中获取列表数据的时候。
目标:
1、所有日期都要在总进度的开始日期—实际结束日期之间
2、开始日期:总进度开始日期之后以及包含总进度的开始日期——实际结束日期之前以及包含实际结束日期
3、实际结束日期:与开始日期同理
4、计划结束日期:在当前行的开始日期之后以及包含开始日期——实际结束日期之前以及包含实际结束日期,(若不想包含,则把- 8.64e7去掉即可)
第一张是编辑,需要在获取列表数据的时候就要进行设置使用范围,
// 获取项目表格数据
async List () {
this.da = JSON.parse(localStorage.getItem('ProgressData'))
const res = await GetSpeed({ projectid: this.da.id })
res.data.forEach((i, index) => {
i.plan = {
disabledDate: (time) => {
if (i.starttime) {
return new Date(time).getTime() < new Date(i.starttime).getTime() - 8.64e7 || new Date(time).getTime() > new Date(res.data[0].endtime).getTime()
}
}
}
i.end = {
disabledDate: (time) => {
if (i.starttime) {
return new Date(time).getTime() < new Date(i.starttime).getTime() - 8.64e7 || new Date(time).getTime() > new Date(res.data[0].endtime).getTime()
}
}
}
i.start = {
disabledDate: (time) => {
if (i.plan_endtime) {
return new Date(time).getTime() > new Date(i.plan_endtime).getTime() || new Date(time).getTime() < new Date(res.data[0].starttime).getTime() - 8.64e7
}
}
}
})
this.tableData = res.data
第二张是新增,既是表单,则在data中设置使用范围即可
data () {
return {
plan_endtime: {
disabledDate: (time) => {
return new Date(time).getTime() < new Date(this.form.starttime).getTime() || new Date(time).getTime() < new Date(this.tableData[0].starttime).getTime() - 8.64e7 || new Date(time).getTime() > new Date(this.tableData[0].endtime).getTime()
}
},
endtime: {
disabledDate: (time) => {
return new Date(time).getTime() < new Date(this.form.starttime).getTime() || new Date(time).getTime() < new Date(this.tableData[0].starttime).getTime() - 8.64e7 || new Date(time).getTime() > new Date(this.tableData[0].endtime).getTime()
}
},
starttime: {
disabledDate: (time) => {
return new Date(time).getTime() > new Date(this.form.plan_endtime).getTime() || new Date(time).getTime() < new Date(this.tableData[0].starttime).getTime() - 8.64e7 || new Date(time).getTime() > new Date(this.tableData[0].endtime).getTime()
}
},
}
},
完整代码
<template>
<div id="pro" class="pro-container">
<div class="center">
<div class="top">
<el-button class="new" type="primary" size="small" @click="Add()"
>新建节点</el-button
>
<div>
<el-button class="aboutCancel" size="small" @click="home()"
>返回项目列表</el-button
>
</div>
</div>
<el-table
ref="tableData"
v-loading="loading"
:cell-style="cellStyle"
:data="tableData"
border
style="width: 100%"
element-loading-text="拼命加载中"
element-loading-spinner="el-icon-loading"
:header-cell-style="{ 'text-align': 'center' }"
>
<el-table-column width="80px" prop="no" label="序号" align="center">
</el-table-column>
<el-table-column align="center" prop="name" label="任务名称">
<template slot-scope="scope">
<div v-if="scope.row.show">
<el-input
v-model="scope.row.name"
placeholder="请输入"
></el-input>
</div>
<div v-else>{{ scope.row.name }}</div>
</template>
</el-table-column>
<el-table-column prop="starttime" label="开始日期" align="center">
<template slot-scope="scope">
<div v-if="scope.row.show">
<el-date-picker
v-model="scope.row.starttime"
type="date"
placeholder="选择日期"
:picker-options="scope.row.start || starttime"
>
</el-date-picker>
</div>
<div v-else>{{ scope.row.starttime | formatDate }}</div>
</template>
</el-table-column>
<el-table-column
prop="plan_endtime"
label="计划结束日期"
align="center"
>
<template slot-scope="scope">
<div v-if="scope.row.show">
<el-date-picker
v-model="scope.row.plan_endtime"
type="date"
placeholder="选择日期"
:picker-options="scope.row.plan || plan_endtime"
>
</el-date-picker>
</div>
<div v-else>{{ scope.row.plan_endtime | formatDate }}</div>
</template>
</el-table-column>
<el-table-column prop="endtime" label="实际结束日期" align="center">
<template slot-scope="scope">
<div v-if="scope.row.show">
<el-date-picker
v-model="scope.row.endtime"
type="date"
placeholder="选择日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
:picker-options="scope.row.end || endtime"
>
</el-date-picker>
</div>
<div v-else>{{ scope.row.endtime | formatDate }}</div>
</template>
</el-table-column>
<el-table-column width="120" prop="day" label="天数" align="center">
<template slot-scope="scope">
{{ scope.row.day }}
</template>
</el-table-column>
<el-table-column prop="change_desc" label="时间变动" align="center">
<template slot-scope="scope">
<div v-if="scope.row.change_desc === ''">正常</div>
<div v-else>
<span>{{ scope.row.change_desc }}</span>
</div>
</template>
</el-table-column>
<el-table-column
width="120"
prop="state"
label="项目状态"
align="center"
>
<template slot-scope="scope">
<div v-show="scope.row.state === 1">未开始</div>
<div v-show="scope.row.state === 2">进行中</div>
<div v-show="scope.row.state === 3">延期</div>
<div v-show="scope.row.state === 4">已结束</div>
</template>
</el-table-column>
<el-table-column width="130px" label="操作" align="center">
<template slot-scope="scope">
<div v-if="scope.$index === 0"></div>
<div v-else>
<div v-if="scope.row.show" style="display: flex">
<el-button
type="text"
@click="change(scope.row, scope.column, scope.$index)"
>保存</el-button
>
<el-button
type="text"
@click="cancel(scope.row, scope.column, scope.$index)"
>取消</el-button
>
</div>
<div v-else style="display: flex">
<el-button
type="text"
:disabled="state"
@click="Edit(scope.row, scope.column, scope.$index)"
>编辑</el-button
>
<el-button
type="text"
:disabled="state"
@click="deleterow(scope.row, scope.column, scope.$index)"
>删除</el-button
>
</div>
</div>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
import { GetSpeed, AddSpeed, DeleteSpeed } from '@/api/pro'
export default {
data () {
return {
plan_endtime: {
disabledDate: (time) => {
return new Date(time).getTime() < new Date(this.form.starttime).getTime() || new Date(time).getTime() < new Date(this.tableData[0].starttime).getTime() - 8.64e7 || new Date(time).getTime() > new Date(this.tableData[0].endtime).getTime()
}
},
endtime: {
disabledDate: (time) => {
return new Date(time).getTime() < new Date(this.form.starttime).getTime() || new Date(time).getTime() < new Date(this.tableData[0].starttime).getTime() - 8.64e7 || new Date(time).getTime() > new Date(this.tableData[0].endtime).getTime()
}
},
starttime: {
disabledDate: (time) => {
return new Date(time).getTime() > new Date(this.form.plan_endtime).getTime() || new Date(time).getTime() < new Date(this.tableData[0].starttime).getTime() - 8.64e7 || new Date(time).getTime() > new Date(this.tableData[0].endtime).getTime()
}
},
tableData: [], // 列表数据
show: false, // 状态
loading: false, // 加载
upload: true,
form: {},//当前行数据
da: {},//上一页数据
state: false,
flagchange: 0, // 表单值是否有改
}
},
created () {
this.List()
},
watch: {
// 监听编辑是否有修改 - departAddForm
form: {
handler (val, oldval) {
this.flagchange++ // 默认值有变更的话
},
deep: true,// 深度监听
},
},
methods: {
// 获取项目表格数据
async List () {
this.loading = true
this.da = JSON.parse(localStorage.getItem('ProgressData'))
const res = await GetSpeed({ projectid: this.da.id })
res.data.forEach((i, index) => {
i.plan = {
disabledDate: (time) => {
if (i.starttime) {
return new Date(time).getTime() < new Date(i.starttime).getTime() - 8.64e7 || new Date(time).getTime() > new Date(res.data[0].endtime).getTime()
}
}
}
i.end = {
disabledDate: (time) => {
if (i.starttime) {
return new Date(time).getTime() < new Date(i.starttime).getTime() - 8.64e7 || new Date(time).getTime() > new Date(res.data[0].endtime).getTime()
}
}
}
i.start = {
disabledDate: (time) => {
if (i.plan_endtime) {
return new Date(time).getTime() > new Date(i.plan_endtime).getTime() || new Date(time).getTime() < new Date(res.data[0].starttime).getTime() - 8.64e7
}
}
}
})
// 重新排序
res.data.forEach((i, index) => {
if (index > 0) {
i.no = 1 + '.' + Number(index)
}
})
this.tableData = res.data
this.loading = false
},
// 编辑
Edit (row, col, index) {
this.$set(row, 'show', true)
this.state = true
this.form = row
// 初始化检测数据,取消的时候判断是否修改过值
this.flagchange = 0
},
// 新建
Add () {
// 判断上一个有没有保存,保存才添加
if (!this.state) {
const index = this.tableData[0].no
this.form = {
id: 0,
no: index + '.' + Number(this.tableData.length),
projectid: this.da.id,
name: '',
starttime: '',
enddtime: '',
plan_endtime: '',
show: true
}
this.tableData.push(this.form)
this.state = true
} else {
this.$message({
type: 'warning',
message: '请先保存上一任务'
})
}
// 初始化检测数据,取消的时候判断是否修改过值
this.flagchange = 0
},
// 删除
async deleterow (row, col, index) {
this.$confirm('是否删除此信息', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const res = await DeleteSpeed({ speedid: row.id })
if (res.code === 200) {
this.$message({
type: 'success',
message: '删除成功'
})
}
this.List()
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
this.form = {}
},
// 保存
async change (row) {
// 必须全部都写,才会保存
if (row.name === '' || row.starttime === '' || row.plan_endtime === '' || row.endtime === '') {
this.$message({
type: 'warning',
message: '请填写完整'
})
} else {
row.show = false
const res = await AddSpeed(this.form)
if (res.code === 200) {
this.$message({
type: 'success',
message: '保存成功'
})
}
this.List()
this.state = false
this.form = {}
}
},
// 取消
cancel (row) {
if (row.name === '' || row.starttime === '' || row.plan_endtime === '' || row.endtime === '') {
row.show = false
this.List()
} else {
if (this.flagchange > 1) { // 说明监听值有变化
this.$confirm('内容还未保存,是否需要保存', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const res = await AddSpeed(this.form)
if (res.code === 200) {
this.$message({
type: 'success',
message: '保存成功'
})
}
}).catch(() => {
this.$message({
type: 'info',
message: '取消保存'
})
})
row.show = false
this.List()
} else {
row.show = false
this.List()
}
}
this.state = false
this.flagchange = 0
},
}
}
</script>
8、一个页面多个表格,每个表格都进行合并
上面的数据格式如下,表格数据是sample_list
<div v-for="(item, index) in changeArr" :key="index">
<div
style="
font-weight: 600;
font-size: 16px;
height: 40px;
line-height: 40px;
padding: 0 10px;
width: 100%;
background-color: #f8f9fb;
"
>
{{ item.name }}
</div>
<el-table :data="item.sample_list" border :span-method="objectSpan">
<el-table-column
v-for="i in cols"
:key="i.label"
:prop="i.prop"
align="center"
:label="i.label"
>
<template slot-scope="scope">
<div style="white-space: pre-wrap">
{{ scope.row[i.prop] }}
</div>
</template>
</el-table-column>
</el-table>
</div>
created() {
this.$forceUpdate();
this.$nextTick(() => {
for (let index = 0; index < changeArr.length; index++) {
for (let jj = 0; jj < changeArr[index].sample_list.length; jj++) {
// 一定要写return
return this.rowspan(changeArr[index].sample_list);
}
}
});
},
methods: {
rowspan(tableData, spanArr, position, spanName) {
// 每次调用清空数据
this.spanArr = [];
this.position = 0;
tableData.forEach((item, index) => {
if (index === 0) {
this.spanArr.push(1);
this.position = 0;
} else {
// 为需要合并查询的项
if (
item.no === tableData[index - 1].no
) {
this.spanArr[this.position] += 1;
this.spanArr.push(0);
} else {
this.spanArr.push(1);
this.position = index;
}
}
});
},
//合并行列
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (
columnIndex === 0 ||
columnIndex === 1 ||
columnIndex === 2 ||
columnIndex === 3 ||
columnIndex === 4 ||
columnIndex === 5 ||
columnIndex === 6 ||
columnIndex === 7
) {
const _row = this.spanArr[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col,
};
}
},
}
目前在created中使用双重循环,return出去this.rowspan(),就不会出现合并错位的现象;
其他地方使用,则需要使用下面的循环方法
//先把嵌套的数组取出来,然后再遍历合并
const table1array = i.table1.map((i) => {
return i.sample_list;
});
table1array.forEach((j) => {
this.rowspan(j);
});
this.$forceUpdate();
有时候使用elementUI的表格合并,一旦数据较多,操作表格较多,有一定概率会出现合并错乱。所以这里会比较建议使用原生的表格合并,只不过数据结构会发生变化,不再是一级数据,而是二级数据。可以看我的另一篇原生表格的合并【原生HTML】表格
9、循环表格,控制字段的显示与隐藏
我这里的表格循环,是分表头和表格内容的,所以:data="tableColumns"和v-for的tableData是不一样的
tableData是表头、tableColumns是内容
<el-table
ref="tableHeight"
:data="tableColumns"
:height="tableHeight"
border
style="width: 100%; margin-top: 1%"
@row-click="rowclick"
>
<template v-for="(item, index) in tableData">
<el-table-column
v-if="item.label !== '编号'"
:key="item.label"
:prop="item.prop"
align="center"
:label="item.label"
>
<template slot-scope="scope">
{{ scope.row[index] }}
</template>
</el-table-column>
</template>
</el-table>
10、tabs中的表格,清空多选状态
this.activeFrom是标签页的v-model,我用的是索引
this.tableData[Number(this.activeFrom)].list是tabs下的表格数据
this.$refs.table[Number(this.activeFrom)]对应表格
this.tableData[Number(this.activeFrom)].list.forEach((row) => {
this.$refs.table[Number(this.activeFrom)].toggleRowSelection(
row,
false
);
});
二、样式
1、斑马纹表格(鼠标划过表格,表格颜色不变)
可以通过指定 Table 组件的 row-class-name 属性来为 Table 中的某一行添加 class,表明该行处于某种状态
<el-table
:row-class-name="tableRowClassName"
stripe
:data="tableData"
style="width: 100%"
>
<el-table-column prop="date" label="编号" align="center">
</el-table-column>
<el-table-column prop="amount" label="总金额" align="center">
</el-table-column>
<el-table-column prop="author" label="创建人" align="center">
</el-table-column>
</el-table>
方法一
methods: {
tableRowClassName ({ row, rowIndex }) {
if (row.sfjg == 1) {
return "el-table__row--striped";
} else {
return "";
}
},
//第二种
tableRowClassName ({ row, rowIndex }) {
if (rowIndex % 2 !== 0) {
return 'el-table__row--striped'
}
},
}
方法二
<style lang="scss">
// 显示的颜色
.el-table--striped .el-table__body tr.el-table__row--striped td {
background-color: #f2f9ff;
}
.el-table__row {
background: #fff;
}
// 鼠标划过表格,表格颜色不变
.el-table--striped .el-table__body tr.el-table__row--striped:hover td {
background-color: #f2f9ff;
}
.el-table--enable-row-hover .el-table__body tr:hover > td {
background: #fff;
}
/* 对应第二种方法:表格内背景颜色 */
.el-table--fit {
border: 1px solid #64717d;
}
.tablewhite {
background-color: #eef1ff;
}
.el-table th > .cell {
color: #fff;
}
</style>
2、动态更改某一个单元格字体颜色
通过 :cell-style="cellStyle" 方法返回一个回调
编辑
<el-table
:row-class-name="tableRowClassName"
stripe
:cell-style="cellStyle"
:data="tableData"
style="width: 100%"
>
</el-table>
methods: {
// 字体颜色
// row为某一行的除操作外的全部数据
// * column为某一列的属性
// * rowIndex为某一行(从0开始数起)
// * columnIndex为某一列(从0开始数起
cellStyle ({ row, column, rowIndex, columnIndex }) {
// 状态列字体颜色
if (row.status === 'deleted' && columnIndex === 7) {
return 'color: red'
} else if (row.status === 'published' && columnIndex ===7) {
return 'color: #10bf5d'
} else {
return 'color: #1a1a1b'
}
},
}
3、表格行与行之间留有缝隙
一种是直接在页面中使用
<style lang="scss">
/* 最外层透明 */
#dashboard .el-table,
#dashboard .el-table__expanded-cell {
background-color: transparent;
}
/* 表格内背景颜色 */
#dashboard .el-table th,
#dashboard .el-table tr,
#dashboard .el-table td {
background-color: transparent;
}
// 表格单元格的样式
.el-table td.el-table__cell div {
background-color: #183847;
border-top: 1px solid #0153bf;
border-bottom: 1px solid #0153bf;
}
// 第一个单元格的左边框
.el-table td.el-table__cell:first-child div {
border-left: 1px solid #0153bf;
}
// 最后一个单元格的有边框
.el-table td.el-table__cell:last-child div {
border-right: 1px solid #0153bf;
}
//el-table既可以滚动又可以自适应
// 表格的滚动条隐藏(table一定要设置行内样式height才有滚动效果,如果还要自适应则设置成height="calc(100%-10rem)")
#dashboard .el-table--scrollable-y ::-webkit-scrollbar {
display: none;
}
// 头部下方线条长度
#dashboard .el-table__header-wrapper {
width: 97%;
}
/* 表格内头部 */
#dashboard .el-table th {
color: #e1e6e9;
border-bottom: 1px solid #0153bf;
}
/* 表格内每单元格样式 */
#dashboard .el-table td {
padding: 0;
background-color: #183847;
border-bottom: 1px solid #0153bf;
}
/* 表格内每行 */
#dashboard .el-table__row {
height: 30px;
background-color: #183847;
}
/* 去除表格内最下面的一条线 */
#dashboard .el-table::before {
height: 0px;
}
// 取消表格鼠标进入高亮显示
.el-table__row:hover > td {
background-color: transparent !important;
}
</style>
第二种在弹窗中使用,弹窗中的表格,不知道为啥,使用上面的样式它不生效,但是下面的就有用
.el-table th {
background-color: transparent !important;
color: #000 !important;
border-bottom: none;
padding-bottom: 0;
}
.el-table tr {
background-color: transparent !important;
color: #000 !important;
border: 1px solid #64707c !important;
}
.el-table__body {
border-collapse: separate;
border-spacing: 0px 10px;
}
.el-table td {
padding: 6px 0;
border: transparent; //表格下边框没有
}
.el-table .el-table__row {
height: 27px;
}
.el-table td.is-center {
border-top: 1px solid #0153bf !important;
border-bottom: 1px solid #0153bf;
}
.el-table td.is-center:first-child {
border-left: 1px solid #0153bf !important;
}
.el-table td.is-center:last-child {
height: 27px;
border-right: 1px solid #0153bf !important;
}
.el-table::before {
height: 0px;
}
4、去掉表格多选框
<style lang="scss" scoped>
//去掉表头多选框
::v-deep .el-table__header-wrapper .el-checkbox {
display: none;
}
</style
5、表格自适应高度,但出现底部空白的现象
其实就是 el-table__body-wrapper的高度大于el-table__body
handleClick(tab, event) {
this.BpmGetList(this.form);//调用接口,刷新数据
this.$nextTick(() => {
this.$refs.tableHeight.doLayout(); //更新完数据之后,重新布局表格,为了防止底部出现空白(如果是在标签页中的表格自适应,那么在标签页中需要加v-if。让他在切换时重新渲染,因为标签页默认都渲染好了)
});
this.$forceUpdate();
},
6、刷新页面,发现表格滚动条不见了
这个原因是因为:页面跳转后,body被加上了一个style="overflow: hidden;这是一个bug!!!
解决办法:
第一种:为body设置属性overflow: auto !important;
第二种:用路由设置属性
router.afterEach((to, from, next) => { document.querySelector("body").setAttribute("style", "overflow: auto !important;")});
但是我是在标签页中的表格,而且表格还是固定高度。放在body上面无效,所以我直接放在了表格中,就有效果了
.el-table {
overflow: auto !important;
}
.el-tabs__content {
overflow: auto !important;
}
这篇文章看完如果您觉得有所收获,认为还行的话,就点个赞收藏一下呗