|
|
|
|
|
<template>
|
|
|
|
|
|
<div class="budget-table">
|
|
|
|
|
|
<!-- 标题 -->
|
|
|
|
|
|
<div class="title">项目经费预算表</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 表单 -->
|
|
|
|
|
|
<el-form :model="budgetForm" label-width="150px" class="budget-form">
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="项目名称">
|
|
|
|
|
|
<el-input v-model="budgetForm.projectName" readonly />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="项目号">
|
|
|
|
|
|
<el-input v-model="budgetForm.projectCode" readonly />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="项目经理">
|
|
|
|
|
|
<el-input v-model="budgetForm.managerId" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="产品经理">
|
|
|
|
|
|
<el-input v-model="budgetForm.productManagerId" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="合同额">
|
|
|
|
|
|
<el-input v-model="budgetForm.contractAmount" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="合同净额">
|
|
|
|
|
|
<el-input v-model="budgetForm.netContractAmount" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="预算成本">
|
|
|
|
|
|
<el-input v-model="budgetForm.budgetCost" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="项目毛利率">
|
|
|
|
|
|
<el-input v-model="budgetForm.budgetRate" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="降成本后预算成本">
|
|
|
|
|
|
<el-input v-model="budgetForm.reduceBudgetCost" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="降成本后预算毛利率">
|
|
|
|
|
|
<el-input v-model="budgetForm.reduceBudgetRate" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="项目预算期间">
|
|
|
|
|
|
<el-input v-model="budgetForm.duringOperation" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="单位">
|
|
|
|
|
|
<el-input v-model="budgetForm.unitId" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 表格 -->
|
|
|
|
|
|
<el-table
|
|
|
|
|
|
:data="budgetDetailData"
|
|
|
|
|
|
border
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
:summary-method="getSummaries"
|
|
|
|
|
|
show-summary
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-table-column prop="sortOrder" label="序号" width="80" align="center" />
|
|
|
|
|
|
<el-table-column prop="budgetItem" label="预算科目名称" min-width="150" />
|
|
|
|
|
|
<el-table-column prop="budgetCost" label="预算成本" width="160" align="right">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-if="scope.row.budgetItem === '运输费' || scope.row.budgetItem === '售后服务费' || scope.row.budgetItem === '其他成本'"
|
|
|
|
|
|
v-model="scope.row.budgetCost"
|
|
|
|
|
|
@input="updateBudgetCost(scope.row)"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<span v-else>{{ formatNumber(scope.row.budgetCost) }}</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="reduceBudgetCost" label="降成本后预算成本" width="160" align="right">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-if="scope.row.budgetItem === '运输费' || scope.row.budgetItem === '售后服务费' || scope.row.budgetItem === '其他成本'"
|
|
|
|
|
|
v-model="scope.row.reduceBudgetCost"
|
|
|
|
|
|
@input="updateReduceBudgetCost(scope.row)"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<span v-else>{{ formatNumber(scope.row.reduceBudgetCost) }}</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="referenceProjectName" label="参考项目" width="280">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input v-model="scope.row.referenceProjectName" />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 备注 -->
|
|
|
|
|
|
<div class="note">注:以上成本均为不含税价格</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
import { ref, reactive, computed, watch } from 'vue'
|
|
|
|
|
|
|
|
|
|
|
|
// 表单数据
|
|
|
|
|
|
const budgetForm = reactive({
|
|
|
|
|
|
budgetId: undefined,
|
|
|
|
|
|
projectId: undefined,
|
|
|
|
|
|
approvedFlag: undefined,
|
|
|
|
|
|
budgetVersion: undefined,
|
|
|
|
|
|
projectCategory: undefined,
|
|
|
|
|
|
projectCode: undefined,
|
|
|
|
|
|
projectName: undefined,
|
|
|
|
|
|
managerId: undefined,
|
|
|
|
|
|
managerName: undefined,
|
|
|
|
|
|
productManagerId: undefined,
|
|
|
|
|
|
productManagerName: undefined,
|
|
|
|
|
|
approveUserId: undefined,
|
|
|
|
|
|
approveUserName: undefined,
|
|
|
|
|
|
contractAmount: undefined,
|
|
|
|
|
|
netContractAmount: undefined,
|
|
|
|
|
|
budgetCost: undefined,
|
|
|
|
|
|
budgetRate: undefined,
|
|
|
|
|
|
reduceBudgetCost: undefined,
|
|
|
|
|
|
reduceBudgetRate: undefined,
|
|
|
|
|
|
duringOperation: undefined,
|
|
|
|
|
|
unitId: undefined,
|
|
|
|
|
|
unitName: undefined,
|
|
|
|
|
|
exportFlag: undefined,
|
|
|
|
|
|
budgetStatus: undefined,
|
|
|
|
|
|
flowStatus: undefined,
|
|
|
|
|
|
contractId: undefined,
|
|
|
|
|
|
remark: undefined,
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 预算数据
|
|
|
|
|
|
const budgetDetailData = ref([
|
|
|
|
|
|
{
|
|
|
|
|
|
sortOrder: 1,
|
|
|
|
|
|
budgetItem: '材料费',
|
|
|
|
|
|
budgetCost: 0,
|
|
|
|
|
|
reduceBudgetCost: 0,
|
|
|
|
|
|
referenceProjectId: undefined,
|
|
|
|
|
|
referenceProjectName:''
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
sortOrder: 2,
|
|
|
|
|
|
budgetItem: '人工费',
|
|
|
|
|
|
budgetCost: 0,
|
|
|
|
|
|
reduceBudgetCost: 0,
|
|
|
|
|
|
referenceProjectId: undefined,
|
|
|
|
|
|
referenceProjectName:''
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
sortOrder: 3,
|
|
|
|
|
|
budgetItem: '安装费',
|
|
|
|
|
|
budgetCost: 0,
|
|
|
|
|
|
reduceBudgetCost: 0,
|
|
|
|
|
|
referenceProjectId: undefined,
|
|
|
|
|
|
referenceProjectName:''
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
sortOrder: 4,
|
|
|
|
|
|
budgetItem: '差旅费',
|
|
|
|
|
|
budgetCost: 0,
|
|
|
|
|
|
reduceBudgetCost: 0,
|
|
|
|
|
|
referenceProjectId: undefined,
|
|
|
|
|
|
referenceProjectName:''
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
sortOrder: 5,
|
|
|
|
|
|
budgetItem: '运输费',
|
|
|
|
|
|
budgetCost: 0,
|
|
|
|
|
|
reduceBudgetCost: 0,
|
|
|
|
|
|
referenceProjectId: undefined,
|
|
|
|
|
|
referenceProjectName:''
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
sortOrder: 6,
|
|
|
|
|
|
budgetItem: '售后服务费',
|
|
|
|
|
|
budgetCost: 0,
|
|
|
|
|
|
reduceBudgetCost: 0,
|
|
|
|
|
|
referenceProjectId: undefined,
|
|
|
|
|
|
referenceProjectName:''
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
sortOrder: 7,
|
|
|
|
|
|
budgetItem: '其他费用',
|
|
|
|
|
|
budgetCost: 0,
|
|
|
|
|
|
reduceBudgetCost: 0,
|
|
|
|
|
|
referenceProjectId: undefined,
|
|
|
|
|
|
referenceProjectName:''
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
sortOrder: 8,
|
|
|
|
|
|
budgetItem: '其他成本',
|
|
|
|
|
|
budgetCost: 0,
|
|
|
|
|
|
reduceBudgetCost: 0,
|
|
|
|
|
|
referenceProjectId: undefined,
|
|
|
|
|
|
referenceProjectName:''
|
|
|
|
|
|
}
|
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化数字
|
|
|
|
|
|
const formatNumber = (value: number) => {
|
|
|
|
|
|
if (!value) return '0.00'
|
|
|
|
|
|
return value.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 合计方法
|
|
|
|
|
|
const getSummaries = (param: any) => {
|
|
|
|
|
|
const { columns, data } = param
|
|
|
|
|
|
const sums: any[] = []
|
|
|
|
|
|
columns.forEach((column: any, index: number) => {
|
|
|
|
|
|
if (index === 1) {
|
|
|
|
|
|
sums[index] = '合计'
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if (index === 0 || index === 4) {
|
|
|
|
|
|
sums[index] = ''
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
const values = data.map((item: any) => Number(item[column.property]))
|
|
|
|
|
|
if (!values.every((value: number) => Number.isNaN(value))) {
|
|
|
|
|
|
sums[index] = values.reduce((prev: number, curr: number) => {
|
|
|
|
|
|
const value = Number(curr)
|
|
|
|
|
|
if (!Number.isNaN(value)) {
|
|
|
|
|
|
return prev + curr
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return prev
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 0)
|
|
|
|
|
|
sums[index] = formatNumber(sums[index])
|
|
|
|
|
|
} else {
|
|
|
|
|
|
sums[index] = ''
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
return sums
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新预算数据的方法(供父组件调用)
|
|
|
|
|
|
const updateBudgetDetailData = (type: string, budgetCost: number, reduceBudgetCost: number) => {
|
|
|
|
|
|
const item = budgetDetailData.value.find(item => item.budgetItem === type)
|
|
|
|
|
|
if (item) {
|
|
|
|
|
|
item.budgetCost = budgetCost
|
|
|
|
|
|
item.reduceBudgetCost = reduceBudgetCost
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新预算成本
|
|
|
|
|
|
const updateBudgetCost = (row: any) => {
|
|
|
|
|
|
row.budgetCost = parseFloat(row.budgetCost) || 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新降成本后预算成本
|
|
|
|
|
|
const updateReduceBudgetCost = (row: any) => {
|
|
|
|
|
|
row.reduceBudgetCost = parseFloat(row.reduceBudgetCost) || 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 暴露方法给父组件
|
|
|
|
|
|
defineExpose({
|
|
|
|
|
|
updateBudgetDetailData,
|
|
|
|
|
|
budgetForm,
|
|
|
|
|
|
budgetDetailData
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 接收项目信息
|
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
|
projectInfo: {
|
|
|
|
|
|
type: Object,
|
|
|
|
|
|
default: () => ({})
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 监听项目信息变化
|
|
|
|
|
|
watch(() => props.projectInfo, (newProjectInfo) => {
|
|
|
|
|
|
if (newProjectInfo) {
|
|
|
|
|
|
budgetForm.projectId = newProjectInfo.projectId || ''
|
|
|
|
|
|
budgetForm.projectName = newProjectInfo.projectName || ''
|
|
|
|
|
|
budgetForm.projectCode = newProjectInfo.projectCode || ''
|
|
|
|
|
|
budgetForm.projectCategory = newProjectInfo.projectCategory || ''
|
|
|
|
|
|
}
|
|
|
|
|
|
}, { deep: true, immediate: true })
|
|
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.budget-table {
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.title {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.budget-form {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.note {
|
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|