采购结算

This commit is contained in:
‘huanghaiixia’
2026-02-12 14:07:35 +08:00
parent c17af80e52
commit b036408017
11 changed files with 844 additions and 190 deletions

View File

@ -28,10 +28,16 @@
import { useMessage } from '/@/hooks/web/useMessage';
import { useI18n } from '/@/hooks/web/useI18n';
import { getLngPngSettleHdrPageAdd} from '/@/api/dayPlan/PngSettleHdr';
import { getLngPngSettleHdrPageAddPur} from '/@/api/dayPlan/PngSettleHdrPur'
import { parseDownloadUrl} from '/@/api/system/file';
import { downloadByUrl } from '/@/utils/file/download';
import { DataFormat, FormatOption, DATE_FORMAT, FormatType } from '/@/utils/dataFormat';
const props = defineProps({
selectType: { type: String, default: 'checkbox' },
pageType: String
});
const { t } = useI18n();
const checked = ref(false)
const codeFormSchema: FormSchema[] = [
@ -60,6 +66,21 @@
{ dataIndex: 'file', title: '附件', align: 'left',width: 200},
{ dataIndex: 'settledSign', title: '已结算', align: 'left',width: 100},
];
const columnsPur: BasicColumn[] = [
{ dataIndex: 'datePlan', title: '计划日期', align: 'left', width: 100},
{ dataIndex: 'dateMea', title: '计量日期', align: 'left',width: 100},
{ dataIndex: 'suSname', title: '供应商', align: 'left', },
{ dataIndex: 'pointUpName', title: '上载点', align: 'left',},
{ dataIndex: 'cuSname', title: '客户', align: 'left',},
{ dataIndex: 'pointDelyName', title: '下载点', align: 'left',},
{ dataIndex: 'comName', title: '交易主体', align: 'left',},
{ dataIndex: 'qtyMeaGj', title: '完成量(吉焦)', align: 'left',width: 120},
{ dataIndex: 'qtyMeaM3', title: '完成量(方)', align: 'left',width: 120},
{ dataIndex: 'rateM3Gj', title: '比值(方/吉焦)', align: 'left',width: 120},
{ dataIndex: 'kpName', title: '采购合同', align: 'left',},
{ dataIndex: 'file', title: '附件', align: 'left',width: 200},
{ dataIndex: 'settledSign', title: '已结算', align: 'left',width: 100},
];
const emit = defineEmits(['success', 'register']);
@ -68,24 +89,21 @@
const rowId = ref('');
const selectedKeys = ref<string[]>([]);
const selectedValues = ref([]);
const props = defineProps({
selectType: { type: String, default: 'checkbox' },
});
const searchParams = ref({})
const tableData = ref([])
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
searchParams.value = data.searchParams || {}
});
const [registerTable, { getDataSource, setTableData, updateTableDataRecord, reload }] = useTable({
const [registerTable, { getDataSource, setTableData, updateTableDataRecord, reload,clearSelectedRowKeys }] = useTable({
title: t('待结算记录'),
api: getLngPngSettleHdrPageAdd,
columns,
api: props.pageType=='supplier'?getLngPngSettleHdrPageAddPur: getLngPngSettleHdrPageAdd,
rowKey: props.pageType=='supplier' ? 'salesPurId': 'salesId',
columns: props.pageType=='supplier' ? columnsPur: columns,
bordered: true,
pagination: true,
@ -95,10 +113,16 @@
schemas: codeFormSchema,
fieldMapToTime: [['datePlan', ['startDate', 'endDate'], 'YYYY-MM-DD']],
showResetButton: true,
resetButtonOptions: {
text: '重置',
onClick: () => {
checked.value = false
},
},
},
immediate: false, // 设置为不立即调用
beforeFetch: (params) => {
return { ...params,page:params.limit,...searchParams.value};
return { ...params,page:params.limit,...searchParams.value,settledSign: checked.value ? 0 : null};
},
afterFetch: (res) => {
tableData.value = res || []
@ -144,7 +168,7 @@
}
};
const checkChange = (val) => {
reload({ searchInfo: { settledSign: checked.value ? 0 : null } });
reload();
}
const handleDownload = (info) => {
const url = parseDownloadUrl(info.response ? info.response.data.fileUrl : info.fileUrl);
@ -166,6 +190,7 @@
return
}
closeModal();
clearSelectedRowKeys()
emit('success', selectedValues.value);
}

View File

@ -32,6 +32,7 @@
import { useMessage } from '/@/hooks/web/useMessage';
import { useI18n } from '/@/hooks/web/useI18n';
import { getLngPngSettleHdrDtlList} from '/@/api/dayPlan/PngSettleHdr';
import { getLngPngSettleHdrDtlListPur} from '/@/api/dayPlan/PngSettleHdrPur';
import { DataFormat, FormatOption, DATE_FORMAT, FormatType } from '/@/utils/dataFormat';
const { t } = useI18n();
@ -49,7 +50,10 @@
];
const emit = defineEmits(['success', 'register']);
const props = defineProps({
pageType: String
});
const { notification } = useMessage();
const isUpdate = ref(true);
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
@ -58,10 +62,14 @@
curRecord.value = data.record || {}
isUpdate.value = !!data?.isUpdate;
isDisable.value = data.isDisable
if (!(curRecord.value.lngPngSettleSalesDtlList || []).length) {
if (!(curRecord.value.lngPngSettleSalesDtlList || []).length || !(curRecord.value.lngPngSettlePurDtlList || []).length) {
getList()
} else {
tableData.value = curRecord.value.lngPngSettleSalesDtlList || []
} else {
if (props.pageType == 'supplier') {
tableData.value = curRecord.value.lngPngSettlePurDtlList || []
} else {
tableData.value = curRecord.value.lngPngSettleSalesDtlList || []
}
tableData.value = DataFormat.format(tableData.value, [
FormatOption.createQty('qtySettleGj'),
FormatOption.createQty('qtySettleM3'),
@ -88,12 +96,15 @@
}
}
const getList = async () => {
let res = await getLngPngSettleHdrDtlList({})
let request = props.pageType=='supplier'?getLngPngSettleHdrDtlListPur: getLngPngSettleHdrDtlList
let obj = {}
if (props.pageType=='supplier') {
obj.salesPurId = curRecord.value.salesPurId
} else {
obj.salesId = curRecord.value.salesId
}
let res = await request(obj)
tableData.value = res || []
// tableData.value.forEach(v => {
// v.priceDesc = v.uomName + (v.uomCode == 'M3' ? v.rateQtyM3 : v.rateQtyGj) + v.priceName
// })
}
async function handleSubmit() {
closeModal();

View File

@ -0,0 +1,269 @@
<template>
<div style="width: 100%">
<div class="btnBox">
<a-button v-if="!disabled" type="primary" style="margin-bottom: 10px;margin-right: 10px;" @click="handleBtn('add')">新增</a-button>
<a-button v-if="!disabled" @click="handleBtn('del')">删除</a-button>
<span>一次结算量(吉焦){{ numObj.qtySettleGjOne }}</span>
<span>多次结算量(吉焦){{ numObj.qtySettleGjNum }}</span>
<span>结算总量(吉焦){{ numObj.qtySettleGjAll }}</span>
<span>结算总金额(){{ numObj.amount }}</span>
</div>
<a-table :columns="columns" :data-source="dataList" :scroll="{x: 1800}" :rowKey="rowKey" :pagination="false" :row-selection="{ selectedRowKeys: selectedKeys, onChange: onSelectChange }">
<template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'operation'">
<a v-if="!disabled" @click="btnCheck(record, index, 'delete')">删除</a>
</template>
<template v-if="column.dataIndex === 'priceDesc'">
<a @click="btnCheck(record, index, 'price')">{{record.priceDesc}}</a>
</template>
<template v-if="column.dataIndex === 'ksName'">
<a @click="btnCheck(record, index, 'ksName')">{{pageType=='supplier'?record.kpName :record.ksName}}</a>
</template>
</template>
</a-table>
<measureListModal @register="registerMeasure" @success="handleSuccessMeasure" :pageType="pageType"></measureListModal>
<priceComposeListModal @register="registerPrice" @success="handleSuccessPrice" :pageType="pageType"></priceComposeListModal>
</div>
</template>
<script lang="ts" setup>
import { Card } from 'ant-design-vue';
import { reactive, ref, watch} from 'vue';
import { useRouter } from 'vue-router';
import { useI18n } from '/@/hooks/web/useI18n';
import { Modal } from 'ant-design-vue';
import { useModal } from '/@/components/Modal';
import { message } from 'ant-design-vue';
import measureListModal from '/@/components/common/measureListModal.vue';
import priceComposeListModal from '/@/components/common/priceComposeListModal.vue';
import { DataFormat, FormatOption, DATE_FORMAT, FormatType } from '/@/utils/dataFormat';
const router = useRouter();
const { t } = useI18n();
const dataList = ref([])
const selectedKeys = ref([])
const numObj = ref({})
const columns = ref([
{ title: t('序号'), dataIndex: 'index', key: 'index', customRender: (column) => `${column.index + 1}` ,width: 80},
{ title: t('计划日期'), dataIndex: 'datePlan', width:120},
{ title: t('提气日期'), dataIndex: 'dateMea', width: 120},
{ title: t('合同名称'), dataIndex: 'ksName', width: 200},
{ title: t('下载点'), dataIndex: 'pointDelyName',width: 150 },
{ title: t('完成量(吉焦)'), dataIndex: 'qtyMeaGj', width: 150},
{ title: t('完成量(方)'), dataIndex: 'qtyMeaM3', width: 120},
{ title: t('结算量(吉焦)'), dataIndex: 'qtySettleGj', width: 140},
{ title: t('结算量(方)'), dataIndex: 'qtySettleM3', width: 130},
{ title: t('结算价格(元/吉焦)'), dataIndex: 'priceGj', width: 180},
{ title: t('结算价格(元/方)'), dataIndex: 'priceM3', width: 170},
{ title: t('结算金额(元)'), dataIndex: 'amount', width: 140},
{ title: t('价格组成'), dataIndex: 'priceDesc', width: 180},
{ title: t('结算次数'), dataIndex: 'settleTimes', width: 100},
{ title: t('操作'), dataIndex: 'operation', width: 80},
]);
const [register, { openModal:openModal}] = useModal();
const [registerPrice, { openModal:openModalPrice}] = useModal();
const [registerMeasure, { openModal:openModalMeasure}] = useModal();
const props = defineProps({
disabled: Boolean,
list: Array,
formState: Object,
pageType: String
});
const rowKey = props.pageType=='supplier' ? 'salesPurId': 'salesId'
const emit = defineEmits(['change']);
const onSelectChange = (rowKeys) => {
selectedKeys.value = rowKeys;
}
const handleBtn = (type) => {
if (type === 'add') {
if (!props.formState.cpCode || !props.formState.comId) {
message.warn(props.pageType == 'customer' ? '请选择客户和交易主体' : '请选择供应商和交易主体')
return
}
let obj = {
cpCode: props.formState.cpCode,
comId: props.formState.comId
}
openModalMeasure(true,{isUpdate: false, searchParams: obj})
} else {
if (!selectedKeys.value.length) {
message.warn('请选择删除数据')
return
}
selectedKeys.value.forEach(i => {
let idx = dataList.value.findIndex(v=>v[rowKey] == i)
idx>-1&&dataList.value.splice(idx, 1)
emit('change', dataList.value)
});
setTimeout(() => {
selectedKeys.value = []
}, 1000);
}
}
const handleSuccessMeasure = (val) => {
val.forEach(i =>{
delete i.lngFileUploadList
})
if (!dataList.value.length) {
dataList.value = val
emit('change', dataList.value)
return
}
val.forEach(v=> {
let idx = dataList.value.findIndex(k=>k[rowKey]==v[rowKey])
idx<0&&dataList.value.push(v)
emit('change', dataList.value)
})
}
const handleSuccessPrice = (arr, curRecord) => {
let qtySettleGj = 0
let qtySettleM3 = 0
let amount = 0
let idx = dataList.value.findIndex(v =>v[rowKey] == curRecord[rowKey])
arr.forEach(v=> {
qtySettleGj+=Number(v.qtySettleGj) || 0
qtySettleM3+=Number(v.qtySettleM3) || 0
amount+=Number(v.amount) || 0
if (idx>-1&&!dataList.value[idx].id) {
v.id = ''
}
})
// price_gj=amount/qty_settle_gj保留4位小数
// price_m3=amount/qty_settle_m3保留4位小数
let priceGj = qtySettleGj ? Number(amount) / Number(qtySettleGj) : '0'
let priceM3 = qtySettleM3 ? Number(amount) / Number(qtySettleM3) : '0'
if (idx > -1) {
dataList.value[idx].qtySettleGj = qtySettleGj.toFixed(3)
dataList.value[idx].qtySettleM3 = qtySettleM3.toFixed(3)
dataList.value[idx].amount = amount.toFixed(2)
dataList.value[idx].priceGj = priceGj.toFixed(4)
dataList.value[idx].priceM3 = priceM3.toFixed(4)
if (props.pageType == 'supplier') {
dataList.value[idx].lngPngSettlePurDtlList = arr
} else {
dataList.value[idx].lngPngSettleSalesDtlList = arr
}
emit('change', dataList.value)
}
}
const btnCheck = (record, index, type) => {
if (type == 'delete') {
dataList.value.splice(index, 1)
emit('change', dataList.value)
}
if (type == 'price'){
openModalPrice(true,{isUpdate: false, record,isDisable: props.disabled})
}
if (type == 'ksName'){
if (props.pageType == 'supplier') {
router.push({
path: '/contract/ContractPurPng/viewForm',
query: {
formPath: 'dayPlan/PngSettleHdrPur',
id: record.kpId,
disabled: true
}
});
return
}
router.push({
path: '/contract/ContractSales/viewForm',
query: {
formPath: 'dayPlan/PngSettleHdr',
id: record.ksId,
disabled: true
}
});
}
}
const getList = () => {
return dataList.value
}
watch(
() => dataList.value,
(val) => {
if (val) {
let qtySettleGjOne = 0
let qtySettleGjNum = 0
let amount = 0
val.forEach(v => {
if (Number(v.settleTimes) == 1){
qtySettleGjOne+=Number((v.qtySettleGj || '').replace(/,/g, '')) || 0
} else {
qtySettleGjNum+=Number((v.qtySettleGj || '').replace(/,/g, '')) || 0
}
amount+=Number((v.amount || '').replace(/,/g, '')) || 0
})
numObj.value.qtySettleGjOne = qtySettleGjOne.toFixed(3)
numObj.value.qtySettleGjNum = qtySettleGjNum.toFixed(3)
numObj.value.qtySettleGjAll = (qtySettleGjOne + qtySettleGjNum).toFixed(3)
numObj.value.amount = amount.toFixed(2)
numObj.value = DataFormat.format({...numObj.value}, [
FormatOption.createQty('qtySettleGjOne'),
FormatOption.createQty('qtySettleGjNum'),
FormatOption.createQty('qtySettleGjAll'),
FormatOption.createAmt('amount'),
]);
}
},
{
immediate: true,
deep: true,
}
);
watch(
() => props.pageType,
(val) => {
if (val) {
let idx1 = columns.value.findIndex(v=>v.dataIndex == 'pointUpName')
let idx2 = columns.value.findIndex(v=>v.dataIndex == 'cuSname')
if (val == 'supplier') {
idx1 < 0 && columns.value.splice(4, 0, { title: t('上载点'), dataIndex: 'pointUpName', width: 200})
idx2 < 0 && columns.value.splice(5, 0, { title: t('客户'), dataIndex: 'cuSname', width: 200})
} else {
idx1>-1 && columns.value.splice(idx1, 1)
idx2>-1 && columns.value.splice(idx2, 1)
}
}
},
{
immediate: true,
deep: true,
}
);
watch(
() => props.disabled,
(val) => {
if (val) {
let idx2 = columns.value.findIndex(v =>v.dataIndex == 'operation')
idx2>-1 && columns.value.splice(idx2, 1)
}
},
{
immediate: true,
deep: true,
}
);
watch(
() => props.list,
async (val) => {
dataList.value = val || []
},
{
immediate: true,
deep: true,
}
);
defineExpose({
getList,
});
</script>
<style lang="less" scoped>
.btnBox {
span {
margin: 0 30px;
}
}
</style>