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

920 lines
26 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div>
<!-- 付款登记审核-->
<xy-dialog
ref="paymentRegistration"
title="付款审核"
:is-show.sync="isShow"
type="form"
class="payment-registration"
:form="paymentRegistrationForm"
:rules="paymentRegistrationRules"
@submit="editor"
>
<template v-slot:extraFormTop>
<div class="payment-registration-row">
<div class="payment-registration-row-title">受款单位</div>
<div class="payment-registration-row-content">{{ contract.supply }}</div>
</div>
<div class="payment-registration-row">
<div class="payment-registration-row-title">合同名称</div>
<div class="payment-registration-row-content">{{ contract.name }}</div>
</div>
<div class="payment-registration-row">
<div class="payment-registration-row-title">合同金额</div>
<div class="payment-registration-row-content">{{ moneyFormat(contract.money) }} </div>
</div>
<div style="display: flex">
<div class="payment-registration-row">
<div class="payment-registration-row-title">已申请金额</div>
<div class="payment-registration-row-content">{{ totalApplyMoney() }} </div>
</div>
<div class="payment-registration-row">
<div class="payment-registration-row-title">已申请笔数</div>
<div class="payment-registration-row-content">{{ payment.length }}</div>
</div>
</div>
<div style="display: flex">
<div class="payment-registration-row">
<div class="payment-registration-row-title">已付金额</div>
<div class="payment-registration-row-content">{{ totalMoney() }} </div>
</div>
<div class="payment-registration-row">
<div class="payment-registration-row-title">支付占比</div>
<div class="payment-registration-row-content">{{ percentPay() }}%</div>
</div>
<div class="payment-registration-row">
<div class="payment-registration-row-title">已付笔数</div>
<div class="payment-registration-row-content">{{ actNumsTotal() }}</div>
<div class="payment-registration-row-content" style="color: #ff0000;padding-left: 16px;cursor: pointer;">
<Poptip :transfer="true">
<div>点击查看列表</div>
<template v-slot:content>
<template v-if="payment&&payment.length>0">
<xy-table :height="200" :list="payment" :table-item="payTable">
<template v-slot:btns>
<p />
</template>
</xy-table>
</template>
<template v-else>
<div style="text-align: center">暂无已付笔数</div>
</template>
</template>
</Poptip>
</div>
</div>
</div>
</template>
<template v-slot:remark>
<div class="xy-table-item">
<div class="xy-table-item-label">备注
</div>
<div class="xy-table-item-content">
{{ paymentRegistrationForm.remark }}
</div>
</div>
</template>
<template #act_date>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>实付日期
</div>
<div class="xy-table-item-content">
<el-date-picker v-model="paymentRegistrationForm.act_date" value-format="yyyy-MM-dd" style="width: 150px;" />
</div>
</div>
</template>
<template v-slot:applyMoney>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>申请付款金额
</div>
<div class="xy-table-item-content xy-table-item-price">
<el-input
v-model="paymentRegistrationForm.applyMoney"
readonly
clearable
placeholder="请填写付款金额"
style="width: 300px;"
/>
</div>
</div>
</template>
<template v-slot:deductionMoney>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>本期扣款金额
</div>
<div class="xy-table-item-content xy-table-item-price">
<el-input
v-model="paymentRegistrationForm.discountMoney"
readonly
clearable
placeholder="请填写扣款金额"
style="width: 300px;"
/>
</div>
</div>
</template>
<template v-slot:type>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>款项类型
</div>
<div class="xy-table-item-content">
<!-- <el-input readonly clearable placeholder="选择款项类型或直接填写其他类型" v-model="paymentRegistrationForm.type" style="width: 300px;"/>-->
<el-select
v-model="paymentRegistrationForm.type"
placeholder="选择款项类型或直接填写其他类型"
style="width: 200px;"
disabled
filterable
allow-create
clearable
>
<el-option v-for="item in paymentType" :key="item" :label="item" :value="item" />
</el-select>
</div>
</div>
</template>
<template v-slot:isLast>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>是否为最后一笔
</div>
<div class="xy-table-item-content">
<el-switch v-model="paymentRegistrationForm.isLast" />
</div>
</div>
</template>
<template v-slot:actMoney>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>实际付款金额
</div>
<div class="xy-table-item-content xy-table-item-price">
<el-input v-model="paymentRegistrationForm.actMoney" placeholder="请填写实际付款金额" style="width: 300px;" />
</div>
</div>
</template>
<template v-slot:moneyWay>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>资金列支渠道
</div>
<div class="xy-table-item-content">
<div class="money-way-tree-container">
<el-tree
ref="moneyWayTree"
:data="planTypes"
:props="defaultProps"
show-checkbox
node-key="id"
:default-checked-keys="paymentRegistrationForm.moneyWay || []"
:check-strictly="false"
@check="handleMoneyWayCheck"
style="width: 300px; max-height: 200px; overflow: auto; border: 1px solid #dcdfe6; border-radius: 4px; padding: 10px;"
/>
</div>
<div class="selected-money-way" v-if="selectedMoneyWayLabels.length > 0" style="margin-top: 10px;">
<div style="margin-bottom: 5px; font-size: 12px; color: #606266;">已选择:</div>
<el-tag
v-for="(item, index) in selectedMoneyWayLabels"
:key="index"
closable
size="small"
style="margin-right: 5px; margin-bottom: 5px;"
@close="removeMoneyWay(item.id)"
>
{{ item.label }}
</el-tag>
</div>
</div>
</div>
</template>
<template v-slot:extraFormBottom>
<div style="display: flex;">
<el-select
v-model="plansSelect.typeName"
clearable
placeholder="请选择预算类型"
style="width: 200px;margin-right:10px"
@change="changeType"
size="small"
>
<el-option disabled value="" style="height:150px;overflow: scroll;">
<el-tree
class="planselsct"
ref="tree1"
style="width:300px"
default-expand-all
:default-checked-keys="checkArr"
:check-strictly="true"
:data="planTypes"
show-checkbox
node-key="id"
highlight-current
:props="defaultProps"
@check="(data, node)=>{return getSelectedNodes(data,node,'tree1')}"
/>
</el-option>
</el-select>
<Input v-model="plansSelect.name" search enter-button="搜 索" placeholder="搜索预算计划.." @on-search="getBudgets" />
</div>
<div class="contract-add-plan" style="min-width: 300px;">
<template v-if="paymentRegistrationForm.plan.length > 0">
<Tag v-for="item in paymentRegistrationForm.plan" :key="item.plan_id" closable color="primary" @on-close="delPlan(item)">{{ item.label }}</Tag>
</template>
</div>
<xy-table
ref="planTable"
:list="plans"
:show-index="false"
:table-item="planTable"
:height="310"
style="margin-top: 10px;"
@select="selectPlan"
>
<template v-slot:btns>
<el-table-column label="使用金额" header-align="center" width="140">
<template slot-scope="scope">
<Input :value="scope.row.use_money" @input="inputMoney($event,scope.row)" />
</template>
</el-table-column>
</template>
</xy-table>
<div style="display: flex;justify-content: flex-end;">
<Page :total="planTotal" show-elevator @on-change="planPageChange" />
</div>
</template>
</xy-dialog>
</div>
</template>
<script>
import {
getparameter
} from '@/api/system/dictionary'
import {
getFundLog,
detailFundLog,
editorFundLog
} from '@/api/paymentRegistration/fundLog'
import {
getBudget
} from '@/api/budget/budget'
import {
detailContract,
editorContract
} from '@/api/contract/contract'
import {
Message
} from 'element-ui'
import {
parseTime,
moneyFormatter,
buildTree
} from '@/utils'
import {
index as getPlanType
} from '@/api/budget/plantype.js'
export default {
data() {
return {
checkArr: [],
defaultProps: {
children: 'children',
label: 'name'
},
planTotal: 0,
pageIndex: 1,
// 付款登记
plans: [],
contract: {},
payment: [], // 合同关联的付款登记
planTypes: [],
planTypes_arr:[],
// 已选择的资金列支渠道标签
selectedMoneyWayLabels: [],
payTable: [{
label: '申请金额',
prop: 'apply_money',
sortable: false,
width: 160,
align: 'right'
},
{
label: '已付金额',
prop: 'act_money',
sortable: false,
width: 160,
align: 'right'
},
{
label: '时间',
prop: 'created_at',
sortable: false,
width: 120,
formatter: (t1, t2, value) => {
return parseTime(new Date(value), '{y}-{m}-{d}')
}
}
],
paymentType: ['预付款', '进度款', '结算款', '质保金'],
isShow: false,
registrationId: '',
paymentRegistrationForm: {
applyMoney: '',
deductionMoney: '',
act_date: '',
type: '',
isLast: false,
plan: [],
remark: '',
actMoney: '',
moneyWay: []
},
paymentRegistrationRules: {
act_date: [{
required: true,
message: '必选'
}],
applyMoney: [{
required: true,
message: '必填'
},
{
pattern: /^(-)?\d+(\.\d+)?$/,
message: '必须为数字'
}
],
deductionMoney: [{
required: true,
message: '必填'
},
{
pattern: /^(-)?\d+(\.\d+)?$/,
message: '必须为数字'
}
],
type: [{
required: true,
message: '必选'
}],
actMoney: [{
required: true,
message: '必填'
},
{
pattern: /^(-)?\d+(\.\d+)?$/,
message: '必须为数字'
}
],
moneyWay: [{
required: true,
message: '必填'
}]
},
plansSelect: {
page: 1,
page_size: 10,
name: '',
type:'',
typeName:'',
},
planTable: [{
sortable: false,
width: 36,
type: 'selection'
},
{
label: '年份',
prop: 'year',
align: 'center',
width: 96
},
{
label: '预算类型',
width: 136,
prop: 'type_detail.name',
// formatter: (cell, data, value) => {
// const res = this.planTypes.filter(item => {
// return item.id === value
// })
// return res[0]?.value || '未知'
// }
},
{
label: '科室',
prop: 'plan_department.name',
width: 100,
align: 'center'
}, {
label: '隶属',
prop: 'pid_info.name',
width: 180,
align: 'left'
},
{
label: '名称',
prop: 'name',
width: 280,
align: 'left'
},
{
label: '计划金额',
prop: 'money',
width: 136,
align: 'right',
customFn: (row) => {
const m1 = row.money
const m2 = row.update_money
return m2 == 0 ? m1 : m2
}
},
{
label: '已经使用',
prop: 'use_money_total',
width: 136,
align: 'right'
}
]
}
},
computed: {
moneyFormat() {
return function(money) {
return moneyFormatter(money)
}
}
},
watch: {
isShow(newVal) {
if (!newVal) {
this.paymentRegistrationForm.actMoney = ''
this.paymentRegistrationForm.moneyWay = []
this.paymentRegistrationForm.plan = []
this.selectedMoneyWayLabels = []
this.$refs.planTable.clearSelection()
// 清空树形选择的选中状态
if (this.$refs.moneyWayTree) {
this.$refs.moneyWayTree.setCheckedKeys([])
}
}
}
},
async mounted() {
await this.getBudgets()
await this.getPlanTypes()
},
methods: {
delPlan(val) {
this.paymentRegistrationForm.plan.map((item, index) => {
if (item.plan_id === val.plan_id) {
this.paymentRegistrationForm.plan.splice(index, 1)
}
})
},
// 合计申请金额
totalApplyMoney() {
let total = 0.00
this.payment.map(item => {
total += Number(item.apply_money)
})
return total.toFixed(2)
},
// 资金列支渠道选择后变化
moneyWayChange() {
// const page = 1
// const pageSize = this.plansSelect.page_size
// const name = this.plansSelect.name
// this.plansSelect = {
// page: page,
// page_size: pageSize,
// name: name
// }
if (this.paymentRegistrationForm.moneyWay) {
const _arr = []
this.paymentRegistrationForm.moneyWay.forEach((item, index) => {
_arr.push(item)
})
// this.plansSelect['type'] = _arr + ''
}
// this.getBudgets()
},
// 处理资金列支渠道树形选择
handleMoneyWayCheck(data, checkedInfo) {
const { checkedKeys, checkedNodes } = checkedInfo
// 过滤出叶子节点(没有子级的节点)
const leafNodes = checkedNodes.filter(node => !node.children || node.children.length === 0)
// 更新选中的值
this.paymentRegistrationForm.moneyWay = leafNodes.map(node => node.id)
// 更新显示的标签
this.selectedMoneyWayLabels = leafNodes.map(node => ({
id: node.id,
label: node.name
}))
// 调用原来的变化处理函数
this.moneyWayChange()
},
// 移除已选择的资金列支渠道
removeMoneyWay(id) {
// 从选中数组中移除
const index = this.paymentRegistrationForm.moneyWay.indexOf(id)
if (index > -1) {
this.paymentRegistrationForm.moneyWay.splice(index, 1)
}
// 从标签数组中移除
const labelIndex = this.selectedMoneyWayLabels.findIndex(item => item.id === id)
if (labelIndex > -1) {
this.selectedMoneyWayLabels.splice(labelIndex, 1)
}
// 更新树形组件的选中状态
this.$nextTick(() => {
this.$refs.moneyWayTree.setCheckedKeys(this.paymentRegistrationForm.moneyWay)
})
// 调用原来的变化处理函数
this.moneyWayChange()
},
// 更新已选择的资金列支渠道标签
updateSelectedMoneyWayLabels() {
if (!this.paymentRegistrationForm.moneyWay || this.paymentRegistrationForm.moneyWay.length === 0) {
this.selectedMoneyWayLabels = []
return
}
// 根据选中的ID数组从planTypes中查找对应的节点信息
const selectedNodes = []
const findNodes = (nodes, ids) => {
nodes.forEach(node => {
if (ids.includes(node.id)) {
selectedNodes.push({
id: node.id,
label: node.name
})
}
if (node.children && node.children.length > 0) {
findNodes(node.children, ids)
}
})
}
findNodes(this.planTypes, this.paymentRegistrationForm.moneyWay)
this.selectedMoneyWayLabels = selectedNodes
// 更新树形组件的选中状态
this.$nextTick(() => {
if (this.$refs.moneyWayTree) {
this.$refs.moneyWayTree.setCheckedKeys(this.paymentRegistrationForm.moneyWay)
}
})
},
inputMoney(e, row) {
row.use_money = e
this.paymentRegistrationForm.plan.forEach(item => {
if (item.plan_id == row.id) {
item.use_money = e
}
})
},
async getPlanTypes() {
const res1 = await getparameter({
number: 'money_way'
})
this.planTypes_arr = res1.detail
const res = await getPlanType({
page_size: 999,
page: 1,
sort_name: 'sort',
sort_type: 'asc',
filter: [{
key: 'year',
op: 'eq',
value: this.$moment().format('YYYY'),
}]
})
this.planTypes = buildTree(res.data)
},
changeType(e){
if(!e){
this.plansSelect.type = ''
this.plansSelect.typeName = ''
}
},
getSelectedNodes(data, node, ref) {
const ref_data = ref || 'tree'
this.$refs[ref_data].setCheckedKeys([])
this.checkArr = []
if (data.children && data.children.length > 0) {
this.$Message.warning('当前节点不可选择')
this.form.type = ''
this.select.type = ''
this.editorForm.type = ''
this.$refs[ref_data].setCheckedKeys([])
return
}
this.$refs[ref_data].setCheckedKeys([]) // 删除所有选中节点
this.$refs[ref_data].setCheckedNodes([data]) // 选中已选中节点
this.plansSelect.type = data.id
this.plansSelect.typeName = data.name
this.getBudgets()
this.$forceUpdate()
},
// 翻页
pageChange(e) {
this.pageIndex = e
this.getBudgets()
},
// 合计金额
totalMoney() {
let total = 0.00
this.payment.map(item => {
total += Number(item.act_money)
})
return moneyFormatter(total)
},
// 已付笔数
actNumsTotal() {
let total = 0
this.payment.map(item => {
if (Number(item.act_money)) {
total++
}
})
return total
},
// 支付占比
percentPay() {
let total = 0
this.payment.map(item => {
total += Number(item.act_money)
})
// 防止除以0
if (!this.contract.money || Number(this.contract.money) === 0) {
return 0
}
return ((total / this.contract.money) * 100).toFixed(2) || 0
},
async getRegistration(id) {
this.registrationId = id
const res = await detailFundLog({
id
})
this.paymentRegistrationForm.type = res.type
this.paymentRegistrationForm.act_date = res.act_date
this.paymentRegistrationForm.isLast = res.is_end === 1
this.paymentRegistrationForm.deductionMoney = res.apply_money
this.paymentRegistrationForm.applyMoney = res.apply_money
this.paymentRegistrationForm.remark = res.remark
for (var m of res.plan_link) {
m.label = m.plan ? m.plan.name : '无计划名称'
}
this.paymentRegistrationForm.plan = res.plan_link
this.paymentRegistrationForm.discountMoney = res.discount_money
this.paymentRegistrationForm.actMoney = res.apply_money
this.paymentRegistrationForm.moneyWay = res.money_way_id?.split(',').map(item => Number(item))
// 更新已选择的资金列支渠道标签
if (this.paymentRegistrationForm.moneyWay && this.paymentRegistrationForm.moneyWay.length > 0) {
this.updateSelectedMoneyWayLabels()
}
await this.getContract(res.contract)
await this.moneyWayChange()
},
// 获取合同信息
async getContract(info) {
this.contract = info
const res = await getFundLog({
contract_id: this.contract.id
})
this.payment = res.data
this.toggleSelection(this.paymentRegistrationForm.plan.map(item => {
return item.plan_id
}))
},
// 确认审核
editor() {
let total = 0
this.paymentRegistrationForm.plan.forEach(item => {
total += Number(item.use_money)
})
console.log(Number(this.paymentRegistrationForm.actMoney).toFixed(2), total.toFixed(2))
if (Number(this.paymentRegistrationForm.actMoney).toFixed(2) !== total.toFixed(2)) {
Message({
type: 'warning',
message: '实际付款金额与计划总金额不符'
})
return
}
editorFundLog({
id: this.registrationId,
contract_id: this.contract.id,
act_money: this.paymentRegistrationForm.actMoney,
status: 1,
act_date: this.paymentRegistrationForm.act_date,
money_way_id: this.paymentRegistrationForm.moneyWay.toString(),
contract_plan_act_links: this.paymentRegistrationForm.plan,
is_end: this.paymentRegistrationForm.isLast ? 1 : 0
}).then(async res => {
// 新增:同步更新合同信息
await editorContract({
id: this.contract.id,
money_way_id: this.paymentRegistrationForm.moneyWay.toString(),
contract_plan_links: this.paymentRegistrationForm.plan
})
this.$emit('refresh')
this.isShow = false
Message({
type: 'success',
message: '操作成功'
})
})
},
// 计划
// 获取预算计划
async getBudgets() {
const res = await getBudget({
top_pid: 1,
sort_name:'year',
sort_type:'DESC',
...this.plansSelect
})
this.plans = res.list.data
this.planTotal = res.list.total
this.toggleSelection(this.paymentRegistrationForm.plan.map(item => {
return item.plan_id
}))
},
planPageChange(e) {
this.plansSelect.page = e
this.getBudgets()
},
selectPlan(sel, row) {
if (sel) {
const select = sel.map(item => {
return {
contract_id: this.contract.id,
plan_id: item.id,
use_money: item.use_money,
new_money: item.money,
label: item.name
}
})
// 说明被删除了
if (sel.filter(plan => {
return plan.id == row.id
}).length == 0) {
this.delPlan({
plan_id: row.id
})
}
const _plan = JSON.parse(JSON.stringify(this.paymentRegistrationForm.plan))
var _select = []
select.map(item => {
if (_plan.filter(plan => {
return plan.plan_id == item.plan_id
}).length == 0) {
_select.push(item)
}
})
this.paymentRegistrationForm.plan = [..._plan, ..._select]
} else {
this.paymentRegistrationForm.plan = []
}
},
// 默认选择计划
toggleSelection(plans) {
if (plans) {
this.plans.filter(plan => {
if (plans.includes(plan.id)) {
plan.use_money = this.paymentRegistrationForm.plan[plans.indexOf(plan.id)].use_money
return true
}
}).map(row => {
this.$refs.planTable.toggleRowSelection(row)
})
} else {
this.$refs.planTable.clearSelection()
}
}
}
}
</script>
<style scoped lang="scss">
.payment-registration {
&-row {
display: flex;
padding: 6px 0;
&-title {
padding: 0 10px;
}
&-content {}
}
}
.xy-table-item-label {
width: 150px;
}
.xy-table-item-price {
position: relative;
&::after {
z-index: 1;
position: absolute;
right: 0;
top: 0;
content: ''
}
::v-deep .el-input__clear {
position: relative;
right: 30px;
z-index: 2;
}
}
::v-deep .planselsct .el-checkbox__input .el-checkbox__inner {
border-radius: 50%;
}
//
.money-way-tree-container {
::v-deep .el-tree {
.el-tree-node__content {
height: 32px;
line-height: 32px;
&:hover {
background-color: #f5f7fa;
}
}
.el-tree-node__label {
font-size: 14px;
}
.el-checkbox {
margin-right: 8px;
}
}
}
.selected-money-way {
.el-tag {
background-color: #e1f3d8;
border-color: #67c23a;
color: #67c23a;
&:hover {
background-color: #f0f9ff;
border-color: #409eff;
color: #409eff;
}
}
}
</style>