1、新建一个custom_table的的组件
<template>
<a-card :title="title">
<template #extra>
<div class="submitBtn">
<a v-if="!edit" @click="editHandle">编辑</a>
<div v-else>
<a-button @click="saveHandle" class="mr-2" type="primary">保存</a-button>
<a-button @click="edit = false">取消</a-button>
</div>
</div>
</template>
<a-table :columns="columns" :data-source="edit ? editData : data" bordered :pagination="false"
:scroll="{y: 400}">
<template #chargeName="{ text,record, index }">
<a-input @change="getAmountHandle" v-if="edit" v-model:value="record.chargeName" placeholder="请输入收费名称" />
<div v-else>
{{ text || ' ' }}
</div>
</template>
<template #currency="{ text,record,index }">
<a-input @change="getAmountHandle" v-if="edit" v-model:value="record.prohibitEditing" placeholder="请输入币种" />
<div v-else>
{{ text || ' ' }}
</div>
</template>
<template #unitPrice="{ text,record,index }">
<a-input @change="getAmountHandle" v-if="edit" v-model:value="record.unitPrice" placeholder="请输入单价" />
<div v-else>
{{ text || ' ' }}
</div>
</template>
<template #billingVolume="{ text,record,index }">
<a-input @change="getAmountHandle" v-if="edit" v-model:value="record.billingVolume" placeholder="请输入计费量" />
<div v-else>
{{ text || ' ' }}
</div>
</template>
<template #exchangeRate="{ text,record,index }">
<a-input @change="getAmountHandle" v-if="edit" v-model:value="record.prohibitEditing" placeholder="请输入汇率" />
<div v-else>
{{ text || ' ' }}
</div>
</template>
<-- 自动计算 -->
<template #amount="{ text,record }">
<div>
{{ text || 0 }}
</div>
</template>
<-- 自动计算 -->
<template #totalAmount="{ text,record }">
<div>
{{ text }}
</div>
</template>
</a-table>
<-- 从最后一项开始删除 -->
<div style="float: right;" v-if="edit" class="mt-2">
<a-popconfirm title="确认删除最后一项吗?" ok-text="确定" cancel-text="取消" @confirm="delHandle">
<a-button type="primary" danger shape="circle">
<template #icon>
<MinusOutlined />
</template>
</a-button>
</a-popconfirm>
<a-button @click="addHandle" type="primary" shape="circle" class="ml-2" style="float: right;">
<template #icon>
<PlusOutlined />
</template>
</a-button>
</div>
</a-card>
</template>
<script lang="ts">
import {
defineComponent,
ref,
onMounted,
reactive,
toRaw,
watch
} from 'vue';
import {
message
} from 'ant-design-vue';
import {
cloneDeep
} from 'lodash-es';
import {
PlusOutlined,
MinusOutlined
} from '@ant-design/icons-vue';
export default defineComponent({
props: ['data', 'title'],
components: {
PlusOutlined,
MinusOutlined,
},
setup(props, context) {
// 表格数据
const data = ref(props.data)
// 表格名称
const title = ref(props.title)
// 是否编辑
let edit = ref(false)
// 编辑的数据
let editData = ref([])
// 需要删除的数据
let delArr = ref([])
// 总金额
let total = ref(0)
// 表头
const columns = reactive([{
title: '收费名称',
dataIndex: 'chargeName',
slots: {
customRender: 'chargeName'
},
},
{
title: '币种',
dataIndex: 'currency',
slots: {
customRender: 'currency'
},
},
{
title: '收费单价',
dataIndex: 'unitPrice',
slots: {
customRender: 'unitPrice'
},
},
{
title: '计费量',
dataIndex: 'billingVolume',
slots: {
customRender: 'billingVolume'
},
},
{
title: '汇率',
dataIndex: 'exchangeRate',
slots: {
customRender: 'exchangeRate'
},
},
{
title: '金额(RMB)',
dataIndex: 'amount',
slots: {
customRender: 'amount'
},
},
{
title: '总计金额(RMB)',
dataIndex: 'totalAmount',
slots: {
customRender: 'totalAmount'
},
align: 'center',
customRender: ({
text,
index
}) => {
// 动态设置单元格
const obj = {
children: text,
props: {},
};
if (index === 0) {
obj.props.rowSpan = !edit.value ? data.value.length : editData.value.length
}
if (index >= 1) {
obj.props.rowSpan = 0;
}
return obj;
},
},
])
// 计算总金额
const getTotal = () => {
let total = 0
editData.value.map(item => {
total += Number(item.amount)
})
editData.value.map(item => {
item.totalAmount = total
})
}
// 计算单条金额
const getAmountHandle = () => {
editData.value.map((item, i) => {
let unitPrice = parseFloat(item.unitPrice) ? parseFloat(item.unitPrice) : 0
let billingVolume = parseFloat(item.billingVolume) ? parseFloat(item.billingVolume) : 0
item.amount = (unitPrice * billingVolume * item
.exchangeRate).toFixed(2)
})
getTotal()
}
// 添加按钮
const addHandle = () => {
editData.value.push({
chargeName: "",
currency: "",
unitPrice: '',
billingVolume: "",
exchangeRate: "",
amount: "",
totalAmount: "",
})
}
// 编辑按钮
const editHandle = () => {
edit.value = true
// 深度拷贝表格数据
editData.value = cloneDeep(data.value)
}
// 删除按钮
const delHandle = () => {
editData.value.pop()
getTotal()
}
// 保存
const saveHandle = () => {
// 用于判断是否有数据未填
let flag = true
// 验证表格数据必填项
editData.value.map((item, i) => {
item.sort = i + 1
if (!item.chargeName || !item.currency || !item
.unitPrice || !item.billingVolume || !item.exchangeRate) {
flag = false
return;
}
item.amount = ((parseFloat(item.unitPrice) * parseFloat(item.billingVolume)) * item
.exchangeRate).toFixed(2)
})
if (!flag) {
message.warning('请完善表格');
return
}
data.value = editData.value
edit.value = false
}
return {
title,
data,
columns,
edit,
editData,
addHandle,
editHandle,
delHandle,
saveHandle,
getAmountHandle
};
}
})
</script>
<style scoped lang="less">
.submitBtn {
/deep/.ant-select-selector,
/deep/.ant-input,
/deep/ .ant-picker,
/deep/ .ant-btn {
height: 30px !important;
line-height: 30px;
padding: 0 10px;
}
}
</style>
2、在父组件中引入
<template>
<CostTable title="费用明细" :data="data" />
</template>
<script lang="ts">
import {
defineComponent,
ref,
} from 'vue';
import CostTable from './costTable.vue'
export default defineComponent({
components: {
CostTable
},
setup(props, context) {
let data= ref([
{
chargeName: '人工费',
currency: 'RMB',
unitPrice: '2',
billingVolume: '3',
exchangeRate: '4',
amount: '12',
}
])
return {
data
};
}
})
</script>