elemnt和antv和ng动态表格的自定义列
帮助
ng:NG-ZORRO
antv:Ant Design Vue
elemnt:element
elment效果图
HTML
<el-card>
<div class="flex">
<el-table :data="tableData" border>
<el-table-column prop="name" label="筛查信息" align="center"> </el-table-column>
<el-table-column v-for="(item, index) in header" :key="index" :prop="item.prop" :label="item.label" align="center">
<template slot="header" slot-scope="scope">
<div class="close">
<el-popconfirm icon="el-icon-info" :ref="`popover-${scope.$index}`" @onConfirm="close(item)" icon-color="red" title="确定删除吗?"
><el-button type="text" slot="reference">
<i class="el-icon-close" />
</el-button>
</el-popconfirm>
</div>
<el-select size="mini" v-model="item.schId" @change="schChange(item)" style=" 100%; margin-bottom: 10px" clearable placeholder="请选择学校">
<el-option v-for="(i, key) in schArr" :key="key" :label="i.schName" :value="i.schId"></el-option>
</el-select>
<el-select size="mini" v-model="item.batchId" @change="batchChange(item)" style=" 100%; margin-bottom: 10px" clearable placeholder="请选择批次">
<el-option v-for="(i, key) in batchArr" v-if="i.checkSchId == item.schId ? true : false" :key="key" :label="i.batchName" :value="i.batchId"></el-option>
</el-select>
<el-select size="mini" v-model="item.gradeId" @change="gradeChange(item)" style=" 100%; margin-bottom: 10px" clearable placeholder="请选择年级">
<el-option v-for="(i, key) in item.gradeArr" :key="key" :label="i.gradeName" :value="i.gradeId"></el-option>
</el-select>
<el-select size="mini" v-model="item.classId" @change="classChange(item)" style=" 100%" clearable placeholder="请选择班级">
<el-option v-for="(i, key) in item.classArr" :key="key" :label="i.className" :value="i.classId"></el-option>
</el-select>
</template>
</el-table-column>
</el-table>
<div class="btn" @click="add">添加对比报表</div>
</div>
</el-card>
CSS
.el-table {
margin-top: 0;
font-size: 12px;
}
.flex {
display: flex;
align-items: flex-start;
}
.btn {
30px;
height: 130px;
text-align: center;
background: #409efe;
display: flex;
justify-content: center;
align-items: center;
color: white;
cursor: pointer;
}
.close {
display: flex;
justify-content: flex-end;
margin-top: -10px;
}
JS
created() {
this.add()
this.add()
this.schlist()
this.batchlist()
},
methods: {
add() {
this.header.push({
prop: `index + ${this.index}`,
schId: '',
batchId: '',
classId: '',
gradeId: '',
gradeArr: [],
classArr: [],
})
this.index += 1
this.schStatistics()
},
async schStatistics() {
let a = []
for (const key in this.header) {
a.push({
str: this.header[key].prop,
schId: this.header[key].schId,
gradeId: this.header[key].gradeId,
classId: this.header[key].classId,
batchId: this.header[key].batchId,
})
}
const res = await this.$http.post('/***/****', a)
if (res.data.code == 0) {
let data = res.data.data
for (const i in data) {
let j = data[i].str
this.tableData[0][j] = data[i].toScreenedPeopleNum + '/' + data[i].screenedPeopleNum
this.tableData[1][j] = data[i].normalVisionPeopleNum + '/' + data[i].normalVisionPeopleRate + '%'
this.tableData[2][j] = data[i].abnormalVisionPeopleNum + '/' + data[i].abnormalVisionPeopleRate + '%'
this.tableData[3][j] = data[i].myopiaPeopleNum + '/' + data[i].myopiaPeopleRate + '%'
this.tableData[4][j] = data[i].mildPeopleNum + '/' + data[i].mildPeopleRate + '%'
this.tableData[5][j] = data[i].moderatePeopleNum + '/' + data[i].moderatePeopleRate + '%'
this.tableData[6][j] = data[i].severePeopleNum + '/' + data[i].severePeopleRate + '%'
}
}
},
}
ng效果图
HTML
<nz-card>
<div class="flex">
<st
#st
(ngModelChange)="st.resetColumns({ emitReload: true })"
[responsive]
resizable
[data]="listOfData"
[columns]="header"
style=" 100%"
>
<ng-template st-row="select" type="title" let-item let-index="index">
<div style="display: flex; justify-content: flex-end; margin-bottom: 10px">
<a
nz-popconfirm
nzPopconfirmTitle="是否删除?"
nzPopconfirmPlacement="bottom"
(nzOnConfirm)="confirm(item)"
(nzOnCancel)="cancel()"
><i nz-icon nzType="close" nzTheme="outline"></i
></a>
</div>
<nz-select
style=" 100%; margin-bottom: 10px"
[(ngModel)]="item.batchId"
nzAllowClear
name="chosedBatch"
nzPlaceHolder="请选择检查批次"
(ngModelChange)="choseBatchChange(item, index)"
>
<nz-option *ngFor="let i of batchList" [nzLabel]="i.batchName" [nzValue]="i.batchId"> </nz-option>
</nz-select>
<nz-select
style=" 100%; margin-bottom: 10px"
[(ngModel)]="item.gradeId"
name="chosedGrade"
nzPlaceHolder="请选择年级"
(ngModelChange)="choseGradeChange(item, index)"
nzAllowClear
>
<nz-option *ngFor="let i of gradeList" [nzLabel]="i.gradeName" [nzValue]="i.gradeId"> </nz-option>
</nz-select>
<nz-select
style=" 100%"
[(ngModel)]="item.classId"
name="chosedClass"
nzPlaceHolder="请选择班级"
(ngModelChange)="choseClassChange(item, index)"
nzAllowClear
>
<nz-option *ngFor="let i of item.classArr" [nzLabel]="i.className" [nzValue]="i.classId"> </nz-option>
</nz-select>
</ng-template>
</st>
<div class="btn" (click)="addRow()">添加对比报表</div>
</div>
</nz-card>
CSS
.btn {
display: flex;
align-items: center;
justify-content: center;
20px;
height: 150px;
padding: 15px;
color: white;
text-align: center;
background: #409efe;
cursor: pointer;
}
.select {
100%;
margin-bottom: 10px;
}
.flex {
display: flex;
align-items: flex-start;
100%;
}
TS
@ViewChild('st', { static: false }) private st: STComponent;
header: any[] = [
{
title: '筛查信息',
index: 'name',
},
];
listOfData: any[] = [
{
name: '待筛查/已筛查人数',
},
{
name: '视力正常人数/比例',
},
{
name: '视力异常人数/比例',
},
{
name: '近视人数/比例',
},
{
name: '轻度异常人数/比例',
},
{
name: '中度异常人数/比例',
},
{
name: '重度异常人数/比例',
},
];
addRow(): void {
this.header.push({
index: `index${this.i}`,
batchId: null,
classId: null,
gradeId: null,
gradeArr: [],
classArr: [],
renderTitle: `select`,
});
this.i++;
this.sch();
}
ngOnInit(): void {
this.addRow();
this.addRow();
this.gradeService.getAllGrades(1, 0, 1).subscribe((res) => {
this.gradeListUploading = false;
if (res && res.code != '0') {
return;
}
this.gradeList = res.data;
});
this.reportService.getSelfSchBatchs().subscribe((res) => {
if (res && res.code != '0') {
return;
}
this.batchList = res.data;
});
this.schoolService.getSelfSchoolInfo().subscribe((res) => {
if (res && res.code != '0') {
return;
}
this.schId = res.data.schId;
});
}
sch() {
let a = [];
for (let key = 1; key < this.header.length; key++) {
a.push({
str: this.header[key].index,
schId: this.schId,
gradeId: this.header[key].gradeId,
classId: this.header[key].classId,
batchId: this.header[key].batchId,
});
}
this.schService.getSchStatistics(a).subscribe((res) => {
if (res && res.code != '0') {
return;
}
let data = res.data;
for (let i = 0; i < data.length; i++) {
let j = res.data[i].str;
this.listOfData[0][j] = data[i].toScreenedPeopleNum + '/' + data[i].screenedPeopleNum;
this.listOfData[1][j] = data[i].normalVisionPeopleNum + '/' + data[i].normalVisionPeopleRate + '%';
this.listOfData[2][j] = data[i].abnormalVisionPeopleNum + '/' + data[i].abnormalVisionPeopleRate + '%';
this.listOfData[3][j] = data[i].myopiaPeopleNum + '/' + data[i].myopiaPeopleRate + '%';
this.listOfData[4][j] = data[i].mildPeopleNum + '/' + data[i].mildPeopleRate + '%';
this.listOfData[5][j] = data[i].moderatePeopleNum + '/' + data[i].moderatePeopleRate + '%';
this.listOfData[6][j] = data[i].severePeopleNum + '/' + data[i].severePeopleRate + '%';
}
this.st.resetColumns({ emitReload: true });
this.st.reset();
// console.log(this.header);
console.log(this.listOfData);
});
}
confirm(e): void {
this.header = this.header.filter((item) => item.index != e.index);
this.sch();
}
antV效果图
HTML
<a-button
class="editable-add-btn"
@click="Visible = true"
style="margin-bottom: 20px"
>
添加规格
</a-button>
<a-table
:columns="columns"
:data-source="dataSource"
bordered
:row-key="(dataSource) => dataSource.key"
:pagination="false"
>
<!-- 动态 -->
<template slot="1" slot-scope="text, record">
<a-input
allow-clear
style=" 100px"
v-model="record.dataVOS['0'].propertyValue"
/>
</template>
<template slot="2" slot-scope="text, record">
<a-input
allow-clear
style=" 100px"
v-model="record.dataVOS['1'].propertyValue"
/>
</template>
<template slot="3" slot-scope="text, record">
<a-input
allow-clear
style=" 100px"
v-model="record.dataVOS['2'].propertyValue"
/>
</template>
<template slot="4" slot-scope="text, record">
<a-input
allow-clear
style=" 100px"
v-model="record.dataVOS['3'].propertyValue"
/>
</template>
<template slot="5" slot-scope="text, record">
<a-input
allow-clear
style=" 100px"
v-model="record.dataVOS['4'].propertyValue"
/>
</template>
<template slot="7" slot-scope="text, record">
<a-input
allow-clear
style=" 100px"
v-model="record.dataVOS['6'].propertyValue"
/>
</template>
<template slot="8" slot-scope="text, record">
<a-input
allow-clear
style=" 100px"
v-model="record.dataVOS['7'].propertyValue"
/>
</template>
<template slot="9" slot-scope="text, record">
<a-input
allow-clear
style=" 100px"
v-model="record.dataVOS['8'].propertyValue"
/>
</template>
<template slot="skuCode" slot-scope="text, record">
<a-input allow-clear style=" 100px" v-model="record.skuCode" />
</template>
<!-- 单位 -->
<template slot="unit" slot-scope="text, record">
<!-- <a-input allow-clear style=" 100px" v-model="record.unit" /> -->
<a-select
allow-clear
v-model="record.unit"
style=" 100px"
show-search
:filter-option="filterOption"
>
<a-select-option value="次">次</a-select-option>
<a-select-option value="件">件</a-select-option>
<a-select-option value="瓶">瓶</a-select-option>
<a-select-option value="片">片</a-select-option>
<a-select-option value="罐">罐</a-select-option>
<a-select-option value="支">支</a-select-option>
<a-select-option value="个">个</a-select-option>
<a-select-option value="cm">cm</a-select-option>
<a-select-option value="m">m</a-select-option>
<a-select-option value="g">g</a-select-option>
<a-select-option value="kg">kg</a-select-option>
<a-select-option value="人">人</a-select-option>
</a-select>
</template>
<!-- 成本价 -->
<template slot="costPrice" slot-scope="text, record"
><a-input
allow-clear
style=" 100px"
v-model="record.costPrice"
/>
</template>
<!-- 零售价 -->
<template slot="retailPrice" slot-scope="text, record">
<a-input
allow-clear
style=" 100px"
v-model="record.retailPrice"
/>
</template>
<!-- 状态 -->
<template slot="isDel" slot-scope="text, record">
<a-switch
checked-children="正常"
un-checked-children="停用"
v-model="record.isDels"
/>
</template>
<!-- 允许折扣 -->
<template slot="isDiscount" slot-scope="text, record">
<a-switch
checked-children="是"
un-checked-children="否"
v-model="record.isDiscount"
/>
</template>
<!-- 允许积分 -->
<template slot="isUsePoint" slot-scope="text, record">
<a-switch
checked-children="是"
un-checked-children="否"
v-model="record.isUsePoint"
/>
</template>
<!-- 图片 -->
<template slot="image" slot-scope="text, record, index">
<div>
<a-upload
:action="url"
:headers="headers"
list-type="picture-card"
method="post"
:file-list="record.imgArr"
@preview="handlePreview"
@change="
(fileList) => {
return handleChange(fileList, index);
}
"
>
<div v-if="record.imgArr.length < 1">
<a-icon type="plus" />
<div class="ant-upload-text">上传</div>
</div>
</a-upload>
<a-modal
:visible="previewVisible"
:footer="null"
@cancel="handleCancel"
>
<img alt="example" style=" 100%" :src="previewImage" />
</a-modal>
</div>
</template>
<!-- 操作 -->
<template slot="operation" slot-scope="text, record">
<a-popconfirm
v-if="dataSource.length > 1"
title="是否删除?"
@confirm="() => onDelete(record)"
>
<a href="javascript:;">删除</a>
</a-popconfirm>
</template>
</a-table>
<a-button
class="editable-add-btn"
@click="TdAdd"
style="margin-top: 20px"
>
添加参数
</a-button>
JS
data(){
return{
// 表格
dataSource: [
{
key: 0,
costPrice: "",
dataVOS: [],
imgArr: [],
image: "",
isDels: true,
isDiscount: true,
isUsePoint: true,
map: {},
productId: "",
propertyId: "",
propertyName: "",
propertyValue: "",
propertyValueId: "",
retailPrice: "",
salesNum: "",
skuCode: "",
stockNum: "",
unit: "",
},
],
size: [
"颜色",
"度数",
"材质",
"重量",
"尺寸",
"规格",
"型号",
"设计",
"容量",
"疗程",
"近视度数",
"散光度数",
"轴位",
"功能",
],
Visible: false,
Loading: false,
count: 1,
counts: 1,
columns: [
{
title: "单位",
dataIndex: "unit",
scopedSlots: { customRender: "unit" },
align: "center",
},
{
title: "成本价",
dataIndex: "costPrice",
scopedSlots: { customRender: "costPrice" },
align: "center",
},
{
title: "零售价",
dataIndex: "retailPrice",
scopedSlots: { customRender: "retailPrice" },
align: "center",
},
{
title: "状态",
scopedSlots: { customRender: "isDel" },
align: "center",
},
{
title: "允许折扣",
scopedSlots: { customRender: "isDiscount" },
align: "center",
},
{
title: "允许积分",
scopedSlots: { customRender: "isUsePoint" },
align: "center",
},
{
title: "条形码(skucode)",
dataIndex: "skuCode",
scopedSlots: { customRender: "skuCode" },
align: "center",
},
{
title: "图片",
dataIndex: "image",
scopedSlots: { customRender: "image" },
align: "center",
},
{
title: "操作",
dataIndex: "operation",
scopedSlots: { customRender: "operation" },
align: "center",
},
],
// 图片
previewVisible: false,
previewImage: "",
headers: {
Authorization: localStorage.getItem("***"),
},
url: process.env.VUE_APP_BASEURL + "/****/****",
}
}
created() {
this.baseProductDetail();
},
methods: {
// 详情
async baseProductDetail() {
let res = await this.$http.get("/***/***", {
params: {
id: this.$props.row.id,
},
});
if (res.data.success == true) {
this.$nextTick(() => {
this.form.setFieldsValue({
brandId: res.data.data.baseProduct.brandId,
categoryId: res.data.data.baseProduct.categoryId,
englishName: res.data.data.baseProduct.englishName,
manufacturer: res.data.data.baseProduct.manufacturer,
name: res.data.data.baseProduct.name,
productCode: res.data.data.baseProduct.productCode,
pyCode: res.data.data.baseProduct.pyCode,
remark: res.data.data.baseProduct.remark,
supplierId: res.data.data.baseProduct.supplierId,
warnNum: res.data.data.baseProduct.warnNum,
warnDay: res.data.data.baseProduct.warnDay,
});
});
if (res.data.data.productSkuList != null) {
let arr = [];
for (const key in res.data.data.productSkuList) {
res.data.data.productSkuList[key].isDels =
res.data.data.productSkuList[key].isDel == 0 ? true : false;
}
this.dataSource = res.data.data.productSkuList;
for (const key in this.dataSource) {
this.dataSource[key].key = this.dataSource[key].id;
arr.push(this.dataSource[key].id);
this.dataSource[key].imgArr = [];
if (this.dataSource[key].image != "") {
this.dataSource[key].imgArr.push({
uid: "-1",
name: "image.png",
status: "done",
response: {
data: this.dataSource[key].image,
},
url: process.env.VUE_APP_BASEURL + this.dataSource[key].image,
});
}
if (this.dataSource[key].dataVOS == null) {
this.dataSource[key].dataVOS = [];
}
}
let max = Math.max(...arr);
this.count = max + 1;
this.dataSource[0].nameArr =
this.dataSource[0].propertyName.split(",");
if (this.dataSource[0].dataVOS.length > 0) {
let Arr = [];
for (const i in this.dataSource[0].dataVOS) {
Arr.push(this.dataSource[0].dataVOS[i].propertyId);
let newData = {
title: (
<div>
{this.dataSource[0].dataVOS[i].propertyName}
<a
onClick={() =>
this.onDel(this.dataSource[0].dataVOS[i].propertyName)
}
>
<a-icon type="close" style="margin-left:5px" />
</a>
</div>
),
key: this.dataSource[0].dataVOS[i].propertyName,
scopedSlots: {
customRender: this.dataSource[0].dataVOS[i].propertyId,
},
align: "center",
};
this.columns.unshift(newData);
}
let Max = Math.max(...Arr);
this.thIndex = Max + 1;
} else {
this.thIndex = 1;
}
}
}
},
// 删除参数
onDelete(key) {
const dataSource = [...this.dataSource];
this.dataSource = dataSource.filter((item) => item.key !== key.key);
this.removeIds.push(key.id);
},
// 删除规格
onDel(key) {
console.log(key);
const columns = [...this.columns];
this.columns = columns.filter((item) => item.key !== key);
console.log(this.dataSource);
if (this.dataSource.length > 0) {
for (const key in this.dataSource) {
for (const i in this.dataSource[key].dataVOS) {
if (this.dataSource[key].dataVOS[i].propertyName == key) {
this.dataSource[key].dataVOS[i].split(i, 1);
}
}
}
}
},
ThAdd() {
const { checkedList } = this;
for (let key = 0; key < checkedList.length; key++) {
for (let i = 0; i < this.columns.length; i++) {
if (this.columns[i].key == checkedList[key]) {
this.$message.error(checkedList[key] + "重复");
this.Visible = false;
return;
}
}
let newData = {
title: (
<div>
{checkedList[key]}
<a onClick={() => this.onDel(checkedList[key])}>
<a-icon type="close" style="margin-left:5px" />
</a>{" "}
</div>
),
key: checkedList[key],
scopedSlots: { customRender: this.thIndex },
align: "center",
};
this.columns.unshift(newData);
for (let i = 0; i < this.dataSource.length; i++) {
if (this.dataSource[i].dataVOS) {
this.dataSource[i].dataVOS.push({
propertyId: this.thIndex,
propertyName: checkedList[key],
propertyValue: "",
propertyValueId: this.thIndex,
});
}
}
this.thIndex += 1;
}
this.Visible = false;
this.checkedList = [];
},
TdAdd() {
const { count } = this;
const newData = {
imgArr: [],
key: this.count,
costPrice: "",
dataVOS: [],
image: "",
isDels: true,
isDiscount: true,
isUsePoint: true,
productId: "",
propertyId: "",
propertyName: "",
propertyValue: "",
propertyValueId: "",
retailPrice: "",
salesNum: "",
skuCode: "",
stockNum: "",
unit: "",
};
if (this.dataSource.length > 0) {
for (const key in this.dataSource[0].dataVOS) {
newData.dataVOS.push({
propertyName: this.dataSource[0].dataVOS[key].propertyName,
propertyId: this.dataSource[0].dataVOS[key].propertyId,
propertyValueId: this.dataSource[0].dataVOS[key].propertyValueId,
});
}
}
this.dataSource.push(newData);
this.count = count + 1;
},
}
坑
问题:ng遇到的问题比较多,可能是我属性用的还不是很熟练,表格的话我是在NG-ALAIN里找到的普通版本的表头和表格是分开的动态列渲染不了(可能是单纯的我菜)