You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

274 lines
7.7 KiB
Vue

<template>
<div class="test-cost-container">
<el-card class="table-card">
<template #header>
<div class="card-header">
<span>测试化验加工费明细</span>
<div class="flex items-center gap-2">
<span class="text-sm" style="white-space: nowrap">行数:</span>
<el-input-number v-model="addRowCount" :min="1" :max="100" :step="1" size="small" />
<el-button type="primary" size="small" @click="addRow">
<el-icon>
<Plus />
</el-icon>
添加
</el-button>
<el-button type="danger" size="small" @click="handleBatchDelete" :disabled="selectedRows.length === 0">
<el-icon>
<Delete />
</el-icon>
删除
</el-button>
</div>
</div>
</template>
<el-table
:data="testData"
border
style="width: 100%"
row-key="id"
show-summary
:summary-method="
() => {
const cols = ['', '', '合计(万元)', '', '', '', '', ''];
cols[cols.length - 1] = formatNumber(totalAmount);
return cols;
}
"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column prop="sortOrder" label="序号" width="80" align="center" />
<el-table-column prop="testingContent" label="测试化验加工的内容" min-width="200">
<template #default="scope">
<el-input v-model="scope.row.testingContent" placeholder="请输入测试化验加工内容" :data-row-index="scope.$index" />
</template>
</el-table-column>
<el-table-column prop="testingUnitName" label="测试化验加工单位" width="200">
<template #default="scope">
<el-input v-model="scope.row.testingUnitName" placeholder="请输入测试化验加工单位" />
</template>
</el-table-column>
<el-table-column prop="unitName" label="单位" width="180">
<template #default="scope">
<el-input v-model="scope.row.unitName" placeholder="请输入单位" />
</template>
</el-table-column>
<el-table-column prop="unitPrice" label="单价(元)" width="160">
<template #default="scope">
<el-input-number v-model="scope.row.unitPrice" placeholder="单价" :min="0" :precision="2" size="small" @change="calculateAmount" />
</template>
</el-table-column>
<el-table-column prop="amount" label="数量" width="160">
<template #default="scope">
<el-input-number v-model="scope.row.amount" :min="0" :precision="2" size="small" @change="calculateAmount" />
</template>
</el-table-column>
<el-table-column prop="price" label="金额(万元)" width="150">
<template #default="scope">
{{ format2TenThousandNumber(scope.row.price) }}
</template>
</el-table-column>
<el-table-column label="操作" width="100" fixed="right">
<template #default="scope">
<el-button type="danger" size="small" @click="handleDelete(scope.$index, scope.row)" icon="Delete">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-4 bg-gray-50 p-3 rounded text-left font-semibold">
<p>注:是指支付给外单位(包括公司内部经济核算单位)的检验、测试、化验及加工等费用。</p>
</div>
</el-card>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, watch, computed } from 'vue';
import { ElMessage } from 'element-plus';
import { rdBudgetTestingCostVO } from '@/api/oa/erp/budgetInfo/rd/rdBudgetTestingCost/types';
// IDprops
const props = defineProps<{
projectId: string;
}>();
// 定义事件
const emit = defineEmits<{
update: [data: { totalAmount: number }];
}>();
// 测试化验加工费数据
const testData = ref<rdBudgetTestingCostVO[]>([]);
const toDeletedTestCostIdList = ref([]);
// 选中的行
const selectedRows = ref<rdBudgetTestingCostVO[]>([]);
// 添加行数
const addRowCount = ref(1);
// 总金额
const totalAmount = computed(() => {
return testData.value.reduce((sum, item) => {
const amountInTenThousand = (Number(item.price) || 0) / 10000;
const formattedAmount = parseFloat(amountInTenThousand.toFixed(2));
return sum + formattedAmount;
}, 0);
});
// 监听项目ID变化
watch(
() => props.projectId,
(newProjectId) => {
if (newProjectId) {
}
},
{ immediate: true }
);
// 格式化数字,元转换为万元
const formatNumber = (value: number) => {
if (!value) return '0.00';
return parseFloat(value).toFixed(2);
};
// 格式化数字,元转换为万元
const format2TenThousandNumber = (value: number) => {
if (!value) return '0.00';
return (parseFloat(value) / 10000).toFixed(2);
};
// 添加新行
const addRow = () => {
const currentSortOrder = testData.value && testData.value.length > 0 ? Math.max(...testData.value.map((item) => item.sortOrder)) : 0;
for (let i = 0; i < addRowCount.value; i++) {
testData.value.push({
sortOrder: currentSortOrder + i + 1,
testingContent: '',
testingUnitName: '',
unitId: undefined,
unitPrice: undefined,
amount: undefined,
price: 0
});
}
// 延迟聚焦到新添加行的第一个输入框
setTimeout(() => {
const firstNewInput = document.querySelector(`[data-row-index="${currentSortOrder}"]`);
if (firstNewInput) {
(firstNewInput as HTMLInputElement).focus();
}
}, 100);
};
// 处理选择变化
const handleSelectionChange = (selection: rdBudgetTestingCostVO[]) => {
selectedRows.value = selection;
};
// 删除单行
const handleDelete = (index: number, row: rdBudgetTestingCostVO) => {
testData.value.splice(index, 1);
// 重新编号
testData.value.forEach((item, index) => {
item.sortOrder = index + 1;
});
if (row.testingCostId) {
toDeletedTestCostIdList.value.push(row.testingCostId);
}
};
// 批量删除
const handleBatchDelete = () => {
if (selectedRows.value.length === 0) {
ElMessage.warning('请选择要删除的行');
return;
}
selectedRows.value.forEach((selectedRow) => {
if (selectedRow.testingCostId) {
toDeletedTestCostIdList.value.push(selectedRow.testingCostId);
}
});
testData.value = testData.value.filter((item) => !selectedRows.value.includes(item));
// 重新编号
testData.value.forEach((item, index) => {
item.sortOrder = index + 1;
});
selectedRows.value = [];
};
// 计算单项金额
const calculateAmount = () => {
testData.value.forEach((item) => {
item.price = (item.amount || 0) * (item.unitPrice || 0);
});
};
// 获取总金额(供父组件调用)
const getTestingAmount = () => {
return {
testingTotal: (Number(totalAmount.value) || 0) * 10000
};
};
// 刷新数据
const refreshData = () => {
if (props.projectId) {
}
};
// 重置数据
const resetData = () => {
testData.value.splice(0, testData.value.length);
totalAmount.value = 0;
};
// 获取表单数据
const getFormData = () => {
return {
testData: [...testData.value],
totalAmount: totalAmount.value
};
};
// 暴露方法给父组件
defineExpose({
testData,
toDeletedTestCostIdList,
getTestingAmount
});
</script>
<style scoped>
.test-cost-container {
padding: 10px;
}
.table-card {
margin-bottom: 20px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.total-row {
margin-top: 20px;
text-align: right;
}
.total-item {
display: inline-flex;
align-items: center;
font-weight: bold;
}
</style>