<template>
|
<div class="mileage-calculation">
|
<div class="calculation-header">
|
<h3>出差里程核算</h3>
|
<div class="header-actions">
|
<el-button type="primary" icon="el-icon-calculator" @click="recalculateAll">
|
重新计算里程
|
</el-button>
|
<el-button icon="el-icon-download" @click="exportReport">
|
导出核算报告
|
</el-button>
|
</div>
|
</div>
|
|
<div class="filters-section">
|
<el-form :model="filters" inline>
|
<el-form-item label="员工姓名">
|
<el-input
|
v-model="filters.employeeName"
|
placeholder="输入员工姓名"
|
clearable
|
/>
|
</el-form-item>
|
<el-form-item label="时间范围">
|
<el-date-picker
|
v-model="filters.dateRange"
|
type="daterange"
|
range-separator="至"
|
start-placeholder="开始日期"
|
end-placeholder="结束日期"
|
value-format="yyyy-MM-dd"
|
/>
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" @click="handleFilter">查询</el-button>
|
<el-button @click="handleReset">重置</el-button>
|
</el-form-item>
|
</el-form>
|
</div>
|
|
<el-table
|
:data="filteredMileageData"
|
border
|
v-loading="loading"
|
style="width: 100%"
|
>
|
<el-table-column prop="tripNumber" label="出差单号" width="140" />
|
<el-table-column prop="employeeName" label="员工姓名" />
|
<el-table-column prop="startCity" label="出发城市" />
|
<el-table-column prop="endCity" label="目的城市" />
|
<el-table-column prop="startDate" label="开始日期" />
|
<el-table-column prop="endDate" label="结束日期" />
|
<el-table-column prop="calculatedDistance" label="核算里程(km)" sortable>
|
<template #default="scope">
|
<el-tag type="info" size="small">
|
{{ scope.row.calculatedDistance }}km
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column prop="fuelCost" label="燃油费用(元)" sortable>
|
<template #default="scope">
|
<span class="amount">¥{{ scope.row.fuelCost }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column prop="allowance" label="出差补贴(元)" sortable>
|
<template #default="scope">
|
<span class="amount">¥{{ scope.row.allowance }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column prop="totalCost" label="总费用(元)" sortable>
|
<template #default="scope">
|
<span class="amount total">¥{{ scope.row.totalCost }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column label="操作" width="150" fixed="right">
|
<template #default="scope">
|
<el-button
|
size="mini"
|
type="text"
|
@click="handleRecalculate(scope.row)"
|
icon="el-icon-refresh"
|
>
|
重新计算
|
</el-button>
|
<el-button
|
size="mini"
|
type="text"
|
@click="handleDetail(scope.row)"
|
icon="el-icon-document"
|
>
|
明细
|
</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<div class="summary-section">
|
<el-card shadow="never">
|
<h4>费用汇总</h4>
|
<el-row :gutter="20">
|
<el-col :span="6">
|
<div class="summary-item">
|
<span class="label">总里程:</span>
|
<span class="value">{{ totalMileage }}公里</span>
|
</div>
|
</el-col>
|
<el-col :span="6">
|
<div class="summary-item">
|
<span class="label">燃油费用:</span>
|
<span class="value">¥{{ totalFuelCost }}</span>
|
</div>
|
</el-col>
|
<el-col :span="6">
|
<div class="summary-item">
|
<span class="label">出差补贴:</span>
|
<span class="value">¥{{ totalAllowance }}</span>
|
</div>
|
</el-col>
|
<el-col :span="6">
|
<div class="summary-item">
|
<span class="label">总费用:</span>
|
<span class="value total">¥{{ totalCost }}</span>
|
</div>
|
</el-col>
|
</el-row>
|
</el-card>
|
</div>
|
|
<div class="pagination-container">
|
<el-pagination
|
:current-page="currentPage"
|
:page-size="pageSize"
|
:total="total"
|
layout="total, sizes, prev, pager, next, jumper"
|
@size-change="handleSizeChange"
|
@current-change="handleCurrentChange"
|
/>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
export default {
|
name: 'MileageCalculation',
|
props: {
|
data: {
|
type: Array,
|
default: () => []
|
},
|
loading: {
|
type: Boolean,
|
default: false
|
}
|
},
|
data() {
|
return {
|
currentPage: 1,
|
pageSize: 10,
|
filters: {
|
employeeName: '',
|
dateRange: []
|
}
|
}
|
},
|
computed: {
|
filteredMileageData() {
|
let data = this.data.filter(item => {
|
const nameMatch = !this.filters.employeeName ||
|
item.employeeName.includes(this.filters.employeeName)
|
const dateMatch = !this.filters.dateRange || this.filters.dateRange.length !== 2 ||
|
(item.startDate >= this.filters.dateRange[0] && item.endDate <= this.filters.dateRange[1])
|
return nameMatch && dateMatch
|
})
|
|
const start = (this.currentPage - 1) * this.pageSize
|
const end = start + this.pageSize
|
return data.slice(start, end)
|
},
|
total() {
|
return this.data.filter(item => {
|
const nameMatch = !this.filters.employeeName ||
|
item.employeeName.includes(this.filters.employeeName)
|
const dateMatch = !this.filters.dateRange || this.filters.dateRange.length !== 2 ||
|
(item.startDate >= this.filters.dateRange[0] && item.endDate <= this.filters.dateRange[1])
|
return nameMatch && dateMatch
|
}).length
|
},
|
totalMileage() {
|
return this.filteredMileageData.reduce((sum, item) =>
|
sum + parseFloat(item.calculatedDistance), 0
|
).toFixed(2)
|
},
|
totalFuelCost() {
|
return this.filteredMileageData.reduce((sum, item) =>
|
sum + parseFloat(item.fuelCost), 0
|
).toFixed(2)
|
},
|
totalAllowance() {
|
return this.filteredMileageData.reduce((sum, item) =>
|
sum + parseFloat(item.allowance), 0
|
).toFixed(2)
|
},
|
totalCost() {
|
return this.filteredMileageData.reduce((sum, item) =>
|
sum + parseFloat(item.totalCost), 0
|
).toFixed(2)
|
}
|
},
|
methods: {
|
handleFilter() {
|
this.currentPage = 1
|
},
|
|
handleReset() {
|
this.filters = {
|
employeeName: '',
|
dateRange: []
|
}
|
this.currentPage = 1
|
},
|
|
recalculateAll() {
|
this.$confirm('确定要重新计算所有出差记录的里程吗?', '提示', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning'
|
}).then(() => {
|
this.$message.success('里程重新计算完成')
|
}).catch(() => {})
|
},
|
|
handleRecalculate(row) {
|
this.$message.info(`重新计算 ${row.employeeName} 的里程`)
|
},
|
|
handleDetail(row) {
|
this.$message.info(`查看 ${row.tripNumber} 的详细费用明细`)
|
},
|
|
exportReport() {
|
this.$message.success('导出功能开发中')
|
},
|
|
handleSizeChange(size) {
|
this.pageSize = size
|
this.currentPage = 1
|
},
|
|
handleCurrentChange(page) {
|
this.currentPage = page
|
}
|
}
|
}
|
</script>
|
|
<style scoped>
|
.mileage-calculation {
|
padding: 20px;
|
}
|
|
.calculation-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 24px;
|
}
|
|
.calculation-header h3 {
|
margin: 0;
|
color: #303133;
|
}
|
|
.header-actions {
|
display: flex;
|
gap: 10px;
|
}
|
|
.filters-section {
|
margin-bottom: 20px;
|
padding: 16px;
|
background: #f8f9fa;
|
border-radius: 4px;
|
}
|
|
.amount {
|
font-weight: 600;
|
color: #409EFF;
|
}
|
|
.amount.total {
|
color: #F56C6C;
|
font-size: 14px;
|
}
|
|
.summary-section {
|
margin: 24px 0;
|
}
|
|
.summary-item {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 8px 0;
|
}
|
|
.summary-item .label {
|
color: #606266;
|
}
|
|
.summary-item .value {
|
font-weight: 600;
|
color: #303133;
|
}
|
|
.summary-item .value.total {
|
color: #F56C6C;
|
font-size: 16px;
|
}
|
|
.pagination-container {
|
display: flex;
|
justify-content: flex-end;
|
margin-top: 20px;
|
}
|
</style>
|