修改合同表格功能

master
linyongLynn 6 months ago
parent 0319d8f987
commit 3c15579876

@ -130,12 +130,12 @@ export function debounce(fn, delay = 500) {
}
// 金额分隔
export function moneyFormatter(money, precision = 2) {
if(!money){
return 0
}
if (Number(money) === 0) {
return 0
export function moneyFormatter(money, precision = 2) {
if(!money){
return 0
}
if (Number(money) === 0) {
return 0
}
return Number(money).toFixed(precision).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
}
@ -183,7 +183,7 @@ export function deepCopy(data) {
} else {
// string,number,bool,null,undefined,symbol
return data
}
}
}
export function requestToForm(requestObj, form) {
// 获取a对象中属性的顺序和值
@ -225,4 +225,87 @@ export function buildTree(data, pid = 0) {
}
}
return tree
}
}
/**
* 数字转中文大写金额
* @param {number} num - 要转换的数字
* @returns {string} 中文大写金额
*/
export function numberToChinese(num) {
if (num === 0) {
return '零元整'
}
const units = ['', '拾', '佰', '仟', '万', '拾', '佰', '仟', '亿', '拾', '佰', '仟', '万']
const digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
const [integer, decimal] = num.toString().split('.')
let result = ''
let intNum = parseInt(integer)
if (intNum === 0) {
result = '零'
} else {
let i = 0
let lastDigit = null
let hasZero = false
while (intNum > 0) {
const digit = intNum % 10
if (digit === 0) {
// 只有当后面有非零数字时才添加"零"
if (!hasZero && lastDigit !== 0) {
result = '零' + result
hasZero = true
}
} else {
let unit = units[i]
// 处理"拾"的特殊情况当十位是1时不写"壹拾",只写"拾"
if (i === 1 && digit === 1) {
result = unit + result
} else {
result = digits[digit] + unit + result
}
hasZero = false
}
lastDigit = digit
intNum = Math.floor(intNum / 10)
i++
}
// 清理末尾的零
result = result.replace(/零+$/, '')
// 清理连续的零
result = result.replace(/零+/g, '零')
}
// 先加上"元"单位
result += '元'
// 处理小数部分
if (decimal) {
const decimalNum = parseInt(decimal)
if (decimalNum > 0) {
const jiao = Math.floor(decimalNum / 10)
const fen = decimalNum % 10
if (jiao > 0) {
result += digits[jiao] + '角'
}
if (fen > 0) {
result += digits[fen] + '分'
}
return result
}
}
// 如果没有小数部分,添加"整"
if (!decimal || parseInt(decimal) === 0) {
result += '整'
}
return result
}

@ -0,0 +1,410 @@
<template>
<div>
<xy-dialog
v-if="form && id"
:is-show.sync="isShow"
title="付款登记编辑"
type="form"
:form="form"
:rules="rules"
@submit="editor"
>
<template v-slot:extraFormTop>
<div class="payment-registration-row">
<div class="payment-registration-row-title">受款单位</div>
<div class="payment-registration-row-content">{{ form.contract.supply }}</div>
</div>
<div class="payment-registration-row">
<div class="payment-registration-row-title">合同名称</div>
<div class="payment-registration-row-content">{{ form.contract.name }}</div>
</div>
<div class="payment-registration-row">
<div class="payment-registration-row-title">合同金额</div>
<div class="payment-registration-row-content">{{ moneyFormat(form.contract.money) }} </div>
</div>
</template>
<template v-slot:apply_money>
<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="form.apply_money" clearable placeholder="请填写付款金额" style="width: 150px;" />
</div>
</div>
</template>
<template v-slot:audit_money>
<div class="xy-table-item">
<div class="xy-table-item-label">审计金额
</div>
<div class="xy-table-item-content xy-table-item-price">
<el-input v-model="contract_form.audit_money" clearable placeholder="请填写审计金额" style="width: 150px;" />
</div>
</div>
</template>
<template v-slot:act_money>
<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="form.act_money" disabled clearable placeholder="请填写实际支付金额" style="width: 150px;" />
</div>
</div>
</template>
<template v-slot:discount_money>
<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="form.discount_money" clearable placeholder="请填写本期扣款金额" style="width: 150px;" />
</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-select
v-model="form.type"
placeholder="选择款项类型或直接填写其他类型"
style="width: 150px;"
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:is_end>
<div class="xy-table-item">
<div class="xy-table-item-label" style="width: 200px;">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>是否为最后一笔
</div>
<div class="xy-table-item-content">
<el-switch :value="form.is_end === 1" @change="e => e ? form.is_end = 1 : form.is_end = 0" />
<!-- @change="toggleSelection"-->
</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">
<el-input
v-model="form.remark"
type="textarea"
clearable
placeholder="进度款日期2022.6.8-2022.7.7"
style="width: 300px;"
/>
</div>
</div>
</template>
<template v-if="false" v-slot:extraFormBottom>
<Input v-model="searchContent" search enter-button=" " placeholder="搜索预算计划.." @on-search="getBudgets" />
<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">
<template slot-scope="scope">
<Input :value="scope.row.use_money" @input="planInput($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="pageChange"/>-->
<!-- </div>-->
</template>
</xy-dialog>
</div>
</template>
<script>
import {
moneyFormatter
} from '@/utils'
import {
editorContract
} from '@/api/contract/contract'
import {
detailFundLog,
editorFundLog
} from '@/api/paymentRegistration/fundLog'
import {
getBudget
} from '@/api/budget/budget'
import {
Message
} from 'element-ui'
export default {
data() {
return {
isShow: false,
id: '',
form: null,
paymentType: ['预付款', '进度款', '结算款', '质保金'],
plansPageIndex: 1,
planTotal: 0,
plans: [],
contract_form: {
audit_money: 0
},
searchContent: '',
planTable: [{
sortable: false,
width: 36,
type: 'selection'
},
{
label: '分类',
prop: 'type',
formatter: (cell, data, value) => {
switch (value) {
case 1:
return '部门预算'
break
case 2:
return '水务计划'
break
case 3:
return '补助经费'
break
case 4:
return '其他'
break
default:
return '未知'
}
}
},
{
label: '名称',
prop: 'name',
align: 'left'
},
{
label: '计划金额',
prop: 'money',
align: 'right'
}
],
rules: {
apply_money: [{
required: true,
message: '必填'
},
{
pattern: /^\d+(\.\d+)?$/,
message: '必须为数字'
}
],
act_money: [{
required: true,
message: '必填'
},
{
pattern: /^\d+(\.\d+)?$/,
message: '必须为数字'
}
],
discount_money: [{
required: true,
message: '必填'
},
{
pattern: /^\d+(\.\d+)?$/,
message: '必须为数字'
}
],
type: [{
required: true,
message: '必选'
}]
}
}
},
computed: {
moneyFormat() {
return function(money) {
return moneyFormatter(money)
}
}
},
mounted() {
},
methods: {
//
planInput(e, row) {
if (e <= (Number(row.money) - Number(row.use_money_total))) {
row.useMoney = e
} else {
Message({
type: 'warning',
message: '使用金额大于剩余预算'
})
row.useMoney = 0
}
},
async getFundLog(id) {
this.id = id
const res = await detailFundLog({
id
})
this.form = res
this.contract_form.audit_money = res.contract.audit_money
console.log(this.form)
},
async getBudgets() {
const res = await getBudget({
name: this.searchContent,
page_size: 10,
page: this.plansPageIndex
})
this.plans = res.list.data
this.planTotal = res.list.total
},
planPageChange(e) {
this.plansPageIndex = e
this.getBudgets()
},
editor() {
editorFundLog(this.form).then(res => {
this.$emit('success')
this.isShow = false
//
editorContract({
id: this.form.contract_id,
audit_money: this.contract_form.audit_money
}).then(r => {
Message({
type: 'success',
message: '操作成功'
})
})
})
},
async toggleSelection(e) {
if (!e) {
return
}
await this.getBudgets()
const plans = this.form.plan_link.map(item => {
return item.plan_id
})
if (plans) {
plans.map((plan, index) => {
const list = this.plans.map(item => {
return item.id
})
if (list.indexOf(plan) != -1) {
this.plans[list.indexOf(plan)].use_money = this.form.plan_link[index].use_money
console.log(this.plans[list.indexOf(plan)])
}
})
this.plans.filter(plan => {
return plans.includes(plan.id)
}).map(row => {
this.$nextTick(() => {
this.$refs['planTable'].toggleRowSelection(row)
})
})
} else {
this.$refs['planTable'].clearSelection()
}
},
selectPlan(sel, row) {
if (sel) {
this.form.plan_link = sel.map(item => {
return {
plan_id: item.id,
use_money: item.useMoney,
new_money: item.money
}
})
} else {
this.form.plan_link = []
}
}
}
}
</script>
<style scoped lang="scss">
.payment-registration {
&-row {
display: flex;
padding: 6px 0;
&-title {
padding: 0 10px;
}
&-content {}
}
}
.xy-table-item-label {
width: 140px;
}
.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;
}
}
.xy-table-item-price-wan {
position: relative;
&::after {
position: absolute;
right: 0;
top: 0;
content: '(万元)'
}
::v-deep .el-input__clear {
position: relative;
right: 46px;
z-index: 2;
}
}
</style>

@ -7,7 +7,6 @@
type="form"
:form="form"
:rules="rules"
@submit="editor"
>
<template v-slot:extraFormTop>
<div class="payment-registration-row">
@ -22,10 +21,34 @@
<div class="payment-registration-row-title">合同金额</div>
<div class="payment-registration-row-content">{{ moneyFormat(form.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">{{ moneyFormat(form.apply_money) }} </div>
</div>
<div class="payment-registration-row">
<div class="payment-registration-row-title">实际支付金额</div>
<div class="payment-registration-row-content">{{ moneyFormat(form.act_money) }} </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">{{ form.type }}</div>
</div>
<div class="payment-registration-row">
<div class="payment-registration-row-title">是否最后一笔</div>
<div class="payment-registration-row-content">{{ form.is_end === 1 ? '是' : '否' }}</div>
</div>
</div>
<div v-if="form.remark" class="payment-registration-row">
<div class="payment-registration-row-title">备注</div>
<div class="payment-registration-row-content">{{ form.remark }}</div>
</div>
</template>
<template v-slot:apply_money>
<div class="xy-table-item">
<div v-if="!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1)" class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>申请付款金额
</div>
@ -35,7 +58,7 @@
</div>
</template>
<template v-slot:audit_money>
<div class="xy-table-item">
<div v-if="!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1)" class="xy-table-item">
<div class="xy-table-item-label">审计金额
</div>
<div class="xy-table-item-content xy-table-item-price">
@ -44,7 +67,7 @@
</div>
</template>
<template v-slot:act_money>
<div class="xy-table-item">
<div v-if="!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1)" class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>实际支付金额
</div>
@ -54,7 +77,7 @@
</div>
</template>
<template v-slot:discount_money>
<div class="xy-table-item">
<div v-if="!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1)" class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>本期扣款金额
</div>
@ -64,7 +87,7 @@
</div>
</template>
<template v-slot:type>
<div class="xy-table-item">
<div v-if="!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1)" class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>款项类型
</div>
@ -83,7 +106,7 @@
</div>
</template>
<template v-slot:is_end>
<div class="xy-table-item">
<div v-if="!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1)" class="xy-table-item">
<div class="xy-table-item-label" style="width: 200px;">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>是否为最后一笔
</div>
@ -95,7 +118,7 @@
</div>
</template>
<template v-slot:remark>
<div class="xy-table-item">
<div v-if="!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1)" class="xy-table-item">
<div class="xy-table-item-label">备注
</div>
<div class="xy-table-item-content">
@ -109,37 +132,90 @@
</div>
</div>
</template>
<template v-if="false" v-slot:extraFormBottom>
<Input v-model="searchContent" search enter-button=" " placeholder="搜索预算计划.." @on-search="getBudgets" />
<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">
<template slot-scope="scope">
<Input :value="scope.row.use_money" @input="planInput($event,scope.row)" />
</template>
</el-table-column>
</template>
</xy-table>
<template v-slot:extraFormBottom>
<!-- 原来的预算计划功能已禁用 -->
<div v-if="false">
<Input v-model="searchContent" search enter-button=" " placeholder="搜索预算计划.." @on-search="getBudgets" />
<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">
<template slot-scope="scope">
<Input :value="scope.row.use_money" @input="planInput($event,scope.row)" />
</template>
</el-table-column>
</template>
</xy-table>
</div>
<!-- 新增的事后支付表格功能 -->
<div v-if="hasPostPaymentForm && currentStep === 2" class="payment-table-section">
<div class="section-header">
<div class="section-title">
事后支付表格
<el-button type="text" style="margin-left: 10px;" @click="openZoomedTable">
<i class="el-icon-zoom-in" /> 放大查看
</el-button>
</div>
</div>
<!-- <div style="display: flex;justify-content: flex-end;">-->
<!-- <Page :total="planTotal" show-elevator @on-change="pageChange"/>-->
<!-- </div>-->
<!-- 根据是否有第二个表格决定显示方式 -->
<div v-if="hasSecondPostPaymentForm">
<!-- 有第二个表格时显示Tab切换 -->
<el-tabs v-model="activePostPaymentTab" @tab-click="handleTabClick">
<el-tab-pane label="事后支付表格1" name="form1">
<div ref="mainTable1" class="payment-table" v-html="forms1" />
</el-tab-pane>
<el-tab-pane label="事后支付表格2" name="form2">
<div ref="mainTable2" class="payment-table" v-html="forms2" />
</el-tab-pane>
</el-tabs>
</div>
<div v-else>
<!-- 只有一个表格时直接显示事后支付表格1 -->
<div ref="mainTable1" class="payment-table" v-html="forms1" />
</div>
</div>
</template>
<template v-slot:footerContent>
<div class="dialog-footer">
<el-button v-if="hasPostPaymentForm && currentStep === 2" @click="prevStep"></el-button>
<el-button v-if="hasPostPaymentForm && currentStep === 1" @click="nextStep"></el-button>
<el-button v-if="(hasPostPaymentForm && currentStep === 2) || (!hasPostPaymentForm)" type="primary" @click="editor"></el-button>
<el-button @click="isShow = false">取消</el-button>
</div>
</template>
</xy-dialog>
<!-- 放大窗口 -->
<el-dialog
:title="getZoomedDialogTitle()"
:visible.sync="zoomedDialogVisible"
width="80%"
:append-to-body="false"
:destroy-on-close="true"
:modal-append-to-body="false"
:top="'5vh'"
custom-class="zoomed-table-dialog"
@close="handleZoomedDialogClose"
>
<div ref="zoomedTable" class="zoomed-table" v-html="getCurrentZoomedForms()" />
</el-dialog>
</div>
</template>
<script>
import {
moneyFormatter
moneyFormatter,
numberToChinese
} from '@/utils'
import {
editorContract
@ -161,6 +237,15 @@ export default {
id: '',
form: null,
paymentType: ['预付款', '进度款', '结算款', '质保金'],
currentStep: 1,
hasPostPaymentForm: false,
hasSecondPostPaymentForm: false,
forms1: null,
forms2: null,
activePostPaymentTab: 'form1',
zoomedDialogVisible: false,
total: 0,
otherTotal: 0,
plansPageIndex: 1,
planTotal: 0,
@ -181,16 +266,12 @@ export default {
switch (value) {
case 1:
return '部门预算'
break
case 2:
return '水务计划'
break
case 3:
return '补助经费'
break
case 4:
return '其他'
break
default:
return '未知'
}
@ -273,6 +354,35 @@ export default {
this.form = res
this.contract_form.audit_money = res.contract.audit_money
console.log(this.form)
//
if (this.form.forms) {
this.hasPostPaymentForm = true
this.currentStep = 1
this.forms1 = this.form.forms
// contract_template2 before_forms
// detailFundLog paymentRegistration
if (this.form.contract && this.form.contract.contract_template2 && this.form.contract.contract_template2.template) {
this.hasSecondPostPaymentForm = true
this.forms2 = this.form.contract.contract_template2.template
} else if (this.form.before_forms) {
// before_forms
this.hasSecondPostPaymentForm = true
this.forms2 = this.form.before_forms
} else {
this.hasSecondPostPaymentForm = false
this.forms2 = null
}
//
} else {
this.hasPostPaymentForm = false
this.hasSecondPostPaymentForm = false
this.currentStep = 1
this.forms1 = null
this.forms2 = null
}
},
async getBudgets() {
const res = await getBudget({
@ -289,7 +399,22 @@ export default {
},
editor() {
editorFundLog(this.form).then(res => {
// form
if (this.hasPostPaymentForm) {
// tab
let currentDom = null
if (this.activePostPaymentTab === 'form1') {
currentDom = this.$refs.mainTable1
} else if (this.activePostPaymentTab === 'form2' && this.hasSecondPostPaymentForm) {
currentDom = this.$refs.mainTable2
}
if (currentDom) {
this.syncFormDomToHtml(currentDom)
}
}
editorFundLog(this.form).then(() => {
this.$emit('success')
this.isShow = false
@ -297,13 +422,356 @@ export default {
editorContract({
id: this.form.contract_id,
audit_money: this.contract_form.audit_money
}).then(r => {
}).then(() => {
Message({
type: 'success',
message: '操作成功'
})
})
}).catch(err => {
console.error('编辑失败:', err)
Message({
type: 'error',
message: '操作失败'
})
})
},
nextStep() {
//
if (this.currentStep === 1) {
if (this.hasPostPaymentForm) {
//
this.currentStep = 2
// amount
this.$nextTick(() => {
this.setupAmountListeners(this.$refs.mainTable1)
this.setupAmountListeners(this.$refs.mainTable2)
})
}
}
},
prevStep() {
//
this.currentStep = 1
},
handleTabClick(tab) {
this.activePostPaymentTab = tab.name
// tab
this.$nextTick(() => {
if (tab.name === 'form1') {
this.setupAmountListeners(this.$refs.mainTable1)
} else if (tab.name === 'form2') {
this.setupAmountListeners(this.$refs.mainTable2)
}
})
},
//
getZoomedDialogTitle() {
return `事后支付表格${this.activePostPaymentTab === 'form1' ? '1' : '2'}`
},
//
getCurrentZoomedForms() {
// tab
if (this.activePostPaymentTab === 'form1') {
return this.forms1
} else if (this.activePostPaymentTab === 'form2') {
return this.forms2
}
return this.forms1
},
//
openZoomedTable() {
// tabDOM
let currentDom = null
if (this.activePostPaymentTab === 'form1') {
currentDom = this.$refs.mainTable1
} else if (this.activePostPaymentTab === 'form2') {
currentDom = this.$refs.mainTable2
}
if (currentDom) {
//
const updatedForms = this.syncFormDomToHtml(currentDom)
//
if (this.activePostPaymentTab === 'form1') {
this.forms1 = updatedForms || this.forms1
} else if (this.activePostPaymentTab === 'form2') {
this.forms2 = updatedForms || this.forms2
}
}
this.zoomedDialogVisible = true
// amount
this.$nextTick(() => {
// 使setTimeoutDOM
setTimeout(() => {
this.setupAmountListeners(this.$refs.zoomedTable)
}, 200)
})
},
handleZoomedDialogClose() {
const dom = this.$refs.zoomedTable
if (dom) {
//
const updatedForms = this.syncFormDomToHtml(dom)
// tab
if (this.activePostPaymentTab === 'form1') {
this.forms1 = updatedForms || this.forms1
} else if (this.activePostPaymentTab === 'form2') {
this.forms2 = updatedForms || this.forms2
}
//
this.$nextTick(() => {
if (this.activePostPaymentTab === 'form1' && this.$refs.mainTable1) {
this.setupAmountListeners(this.$refs.mainTable1)
} else if (this.activePostPaymentTab === 'form2' && this.$refs.mainTable2) {
this.setupAmountListeners(this.$refs.mainTable2)
}
})
}
this.zoomedDialogVisible = false
},
syncFormDomToHtml(dom) {
if (!dom) return ''
const inputs = dom.querySelectorAll('input, select, textarea')
inputs.forEach(input => {
const fieldName = input.getAttribute('data-field')
if (fieldName) {
if (input.type === 'checkbox' || input.type === 'radio') {
const checkedInput = dom.querySelector(`[data-field="${fieldName}"]:checked`)
if (checkedInput) {
checkedInput.setAttribute('checked', 'checked')
}
} else {
if (input.tagName.toLowerCase() === 'textarea') {
input.textContent = input.value || ''
} else {
input.setAttribute('value', input.value || '')
}
}
}
})
// form.forms
this.form.forms = dom.innerHTML
return dom.innerHTML
},
setupAmountListeners(dom) {
if (!dom) return
setTimeout(() => {
// wan, qian, bai, shi, yuan, jiao, fen
const fieldPrefixes = ['wan', 'qian', 'bai', 'shi', 'yuan', 'jiao', 'fen', 'amount']
fieldPrefixes.forEach(prefix => {
const inputs = dom.querySelectorAll(`input[data-field^="${prefix}"]`)
inputs.forEach(input => {
input.removeEventListener('input', this.calculateTotal)
input.removeEventListener('change', this.calculateTotal)
input.removeEventListener('blur', this.calculateTotal)
input.addEventListener('input', this.calculateTotal)
input.addEventListener('change', this.calculateTotal)
input.addEventListener('blur', this.calculateTotal)
})
})
}, 100)
},
calculateTotal() {
// tabDOM
let currentDom = null
if (this.activePostPaymentTab === 'form1') {
currentDom = this.$refs.mainTable1
} else if (this.activePostPaymentTab === 'form2') {
currentDom = this.$refs.mainTable2
}
if (currentDom) {
this.calculateTableTotal(currentDom)
}
//
if (this.$refs.zoomedTable) {
this.calculateTableTotal(this.$refs.zoomedTable)
}
},
calculateTableTotal(dom) {
if (!dom) return
let wanTotal = 0
const wanAmountInputs = dom.querySelectorAll('input[data-field^="wan"]')
wanAmountInputs.forEach(input => {
const value = parseFloat(input.value) || 0
wanTotal += value
})
const wanInput = dom.querySelector('input[data-field="wTotal"]')
if (wanInput) {
wanInput.value = wanTotal === 0 ? '0' : wanTotal
}
let qianTotal = 0
const qianAmountInputs = dom.querySelectorAll('input[data-field^="qian"]')
qianAmountInputs.forEach(input => {
const value = parseFloat(input.value) || 0
qianTotal += value
})
const qianInput = dom.querySelector('input[data-field="qTotal"]')
if (qianInput) {
qianInput.value = qianTotal === 0 ? '0' : qianTotal
}
let baiTotal = 0
const baiAmountInputs = dom.querySelectorAll('input[data-field^="bai"]')
baiAmountInputs.forEach(input => {
const value = parseFloat(input.value) || 0
baiTotal += value
})
const baiInput = dom.querySelector('input[data-field="bTotal"]')
if (baiInput) {
baiInput.value = baiTotal === 0 ? '0' : baiTotal
}
let shiTotal = 0
const shiAmountInputs = dom.querySelectorAll('input[data-field^="shi"]')
shiAmountInputs.forEach(input => {
const value = parseFloat(input.value) || 0
shiTotal += value
})
const shiInput = dom.querySelector('input[data-field="sTotal"]')
if (shiInput) {
shiInput.value = shiTotal === 0 ? '0' : shiTotal
}
let yuanTotal = 0
const yuanAmountInputs = dom.querySelectorAll('input[data-field^="yuan"]')
yuanAmountInputs.forEach(input => {
const value = parseFloat(input.value) || 0
yuanTotal += value
})
const yuanInput = dom.querySelector('input[data-field="yTotal"]')
if (yuanInput) {
yuanInput.value = yuanTotal === 0 ? '0' : yuanTotal
}
let jiaoTotal = 0
const jiaoAmountInputs = dom.querySelectorAll('input[data-field^="jiao"]')
jiaoAmountInputs.forEach(input => {
const value = parseFloat(input.value) || 0
jiaoTotal += value
})
const jiaoInput = dom.querySelector('input[data-field="jTotal"]')
if (jiaoInput) {
jiaoInput.value = jiaoTotal === 0 ? '0' : jiaoTotal
}
let fenTotal = 0
const fenAmountInputs = dom.querySelectorAll('input[data-field^="fen"]')
fenAmountInputs.forEach(input => {
const value = parseFloat(input.value) || 0
fenTotal += value
})
const fenInput = dom.querySelector('input[data-field="fTotal"]')
if (fenInput) {
fenInput.value = fenTotal === 0 ? '0' : fenTotal
}
//
if (fenTotal >= 10) {
jiaoTotal += Math.floor(fenTotal / 10)
fenTotal = fenTotal % 10
}
if (jiaoTotal >= 10) {
yuanTotal += Math.floor(jiaoTotal / 10)
jiaoTotal = jiaoTotal % 10
}
if (yuanTotal >= 10) {
shiTotal += Math.floor(yuanTotal / 10)
yuanTotal = yuanTotal % 10
}
if (shiTotal >= 10) {
baiTotal += Math.floor(shiTotal / 10)
shiTotal = shiTotal % 10
}
if (baiTotal >= 10) {
qianTotal += Math.floor(baiTotal / 10)
baiTotal = baiTotal % 10
}
if (qianTotal >= 10) {
wanTotal += Math.floor(qianTotal / 10)
qianTotal = qianTotal % 10
}
// input
const totalAmount = wanTotal * 10000 + qianTotal * 1000 + baiTotal * 100 + shiTotal * 10 + yuanTotal + jiaoTotal * 0.1 + fenTotal * 0.01
if (wanInput) {
wanInput.value = totalAmount >= 10000 ? (wanTotal === 0 ? '0' : wanTotal) : ''
}
if (qianInput) {
qianInput.value = totalAmount >= 1000 ? (qianTotal === 0 ? '0' : qianTotal) : ''
}
if (baiInput) {
baiInput.value = totalAmount >= 100 ? (baiTotal === 0 ? '0' : baiTotal) : ''
}
if (shiInput) {
shiInput.value = totalAmount >= 10 ? (shiTotal === 0 ? '0' : shiTotal) : ''
}
if (yuanInput) {
yuanInput.value = totalAmount >= 1 ? (yuanTotal === 0 ? '0' : yuanTotal) : ''
}
if (jiaoInput) {
jiaoInput.value = totalAmount >= 0.1 ? (jiaoTotal === 0 ? '0' : jiaoTotal) : ''
}
if (fenInput) {
fenInput.value = totalAmount >= 0.01 ? (fenTotal === 0 ? '0' : fenTotal) : ''
}
this.otherTotal = wanTotal * 10000 + qianTotal * 1000 + baiTotal * 100 + shiTotal * 10 + yuanTotal + jiaoTotal * 0.1 + fenTotal * 0.01
this.otherTotal = parseFloat(this.otherTotal.toFixed(2))
this.total = 0
const amountInputs = dom.querySelectorAll('input[data-field^="amount"]')
amountInputs.forEach(input => {
const value = parseFloat(input.value) || 0
this.total += value
})
const totalInput = dom.querySelector('input[data-field="total"]')
if (totalInput) {
if (this.total === 0) {
this.total = parseFloat(totalInput.value.replace(/¥/g, '')) || 0
} else {
totalInput.value = '¥' + this.total.toFixed(2)
}
}
//
const upperCaseInput = dom.querySelector('input[data-field="upperCaseAmount"]')
if (upperCaseInput) {
if (this.otherTotal !== 0) {
upperCaseInput.value = numberToChinese(this.otherTotal)
} else {
upperCaseInput.value = numberToChinese(this.total)
}
}
},
async toggleSelection(e) {
@ -319,7 +787,7 @@ export default {
const list = this.plans.map(item => {
return item.id
})
if (list.indexOf(plan) != -1) {
if (list.indexOf(plan) !== -1) {
this.plans[list.indexOf(plan)].use_money = this.form.plan_link[index].use_money
console.log(this.plans[list.indexOf(plan)])
}
@ -335,7 +803,7 @@ export default {
this.$refs['planTable'].clearSelection()
}
},
selectPlan(sel, row) {
selectPlan(sel) {
if (sel) {
this.form.plan_link = sel.map(item => {
return {
@ -365,7 +833,9 @@ export default {
padding: 0 10px;
}
&-content {}
&-content {
/* empty */
}
}
}
@ -407,4 +877,176 @@ export default {
z-index: 2;
}
}
.payment-table-section {
margin-top: 20px;
border-top: 1px solid #e6e6e6;
padding-top: 20px;
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
.section-title {
font-size: 16px;
font-weight: 600;
}
}
}
.payment-table {
width: 100%;
overflow-x: auto;
::v-deep table {
width: 100%;
border-collapse: collapse;
td {
border: 1px solid #000;
padding: 8px;
text-align: center;
vertical-align: middle;
}
}
::v-deep input {
width: 100%;
height: 32px;
padding: 4px 8px;
border: 1px solid #DCDFE6;
border-radius: 4px;
background: #fff;
color: #333;
font-size: 14px;
text-align: center;
box-shadow: 0 0 4px rgba(220, 223, 230, 0.2);
&:focus {
outline: none;
border-color: #409EFF;
box-shadow: 0 0 8px rgba(64, 158, 255, 0.3);
}
}
::v-deep textarea {
width: 100%;
min-height: 80px;
padding: 4px 8px;
border: 1px solid #DCDFE6;
border-radius: 4px;
background: #fff;
color: #333;
font-size: 14px;
resize: vertical;
box-shadow: 0 0 4px rgba(220, 223, 230, 0.2);
&:focus {
outline: none;
border-color: #409EFF;
box-shadow: 0 0 8px rgba(64, 158, 255, 0.3);
}
}
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
}
::v-deep .zoomed-table-dialog {
position: fixed;
top: 5vh;
left: 50%;
transform: translateX(-50%);
margin: 0 !important;
max-height: 90vh;
display: flex;
flex-direction: column;
z-index: 2000;
.el-dialog__header {
padding: 15px 20px;
margin: 0;
border-bottom: 1px solid #EBEEF5;
}
.el-dialog__body {
flex: 1;
padding: 20px;
overflow-y: auto;
margin: 0;
max-height: calc(90vh - 120px);
}
.el-dialog__footer {
padding: 15px 20px;
margin: 0;
border-top: 1px solid #EBEEF5;
}
}
::v-deep .el-dialog__wrapper {
padding-top: 0 !important;
display: flex;
align-items: center;
justify-content: center;
}
.zoomed-table {
width: 100%;
::v-deep table {
width: 100%;
border-collapse: collapse;
td {
border: 1px solid #000;
padding: 8px;
text-align: center;
vertical-align: middle;
}
}
::v-deep input {
width: 100%;
height: 32px;
padding: 4px 8px;
border: 1px solid #DCDFE6;
border-radius: 4px;
background: #fff;
color: #333;
font-size: 14px;
text-align: center;
box-shadow: 0 0 4px rgba(220, 223, 230, 0.2);
&:focus {
outline: none;
border-color: #409EFF;
box-shadow: 0 0 8px rgba(64, 158, 255, 0.3);
}
}
::v-deep textarea {
width: 100%;
min-height: 80px;
padding: 4px 8px;
border: 1px solid #DCDFE6;
border-radius: 4px;
background: #fff;
color: #333;
font-size: 14px;
resize: vertical;
box-shadow: 0 0 4px rgba(220, 223, 230, 0.2);
&:focus {
outline: none;
border-color: #409EFF;
box-shadow: 0 0 8px rgba(64, 158, 255, 0.3);
}
}
}
</style>

@ -153,7 +153,7 @@
</template> -->
<template v-slot:applyMoney>
<div v-if="contract_category && contract_category.show_apply_money === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 2))" class="xy-table-item">
<div v-if="contract_category && contract_category.show_apply_money === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1))" class="xy-table-item">
<div class="xy-table-item-label">
<span v-if="contract_category && contract_category.required_apply_money === 1" style="color: red;font-weight: 600;padding-right: 4px;">*</span>
</div>
@ -170,7 +170,7 @@
</template>
<template v-slot:audit_money>
<div v-if="contract_category && contract_category.show_audit_money === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 2))" class="xy-table-item">
<div v-if="contract_category && contract_category.show_audit_money === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1))" class="xy-table-item">
<div class="xy-table-item-label">
<span v-if="contract_category && contract_category.required_audit_money === 1" style="color: red;font-weight: 600;padding-right: 4px;">*</span>
</div>
@ -181,7 +181,7 @@
</template>
<template v-slot:deductionMoney>
<div v-if="contract_category && contract_category.show_discount_money === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 2))" class="xy-table-item">
<div v-if="contract_category && contract_category.show_discount_money === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1))" class="xy-table-item">
<div class="xy-table-item-label">
<span v-if="contract_category && contract_category.required_discount_money === 1" style="color: red;font-weight: 600;padding-right: 4px;">*</span>
</div>
@ -197,7 +197,7 @@
</template>
<template v-slot:remark>
<div v-if="contract_category && contract_category.show_remark === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 2))" class="xy-table-item">
<div v-if="contract_category && contract_category.show_remark === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1))" class="xy-table-item">
<div class="xy-table-item-label">
<span v-if="contract_category && contract_category.required_remark === 1" style="color: red;font-weight: 600;padding-right: 4px;">*</span>
</div>
@ -214,7 +214,7 @@
</template>
<template v-slot:type>
<div v-if="contract_category && contract_category.show_type === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 2))" class="xy-table-item">
<div v-if="contract_category && contract_category.show_type === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1))" class="xy-table-item">
<div class="xy-table-item-label">
<span v-if="contract_category && contract_category.required_type === 1" style="color: red;font-weight: 600;padding-right: 4px;">*</span>
</div>
@ -234,7 +234,7 @@
</template>
<template v-slot:isLast>
<div v-if="contract_category && contract_category.show_is_end === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 2))" class="xy-table-item">
<div v-if="contract_category && contract_category.show_is_end === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1))" class="xy-table-item">
<div class="xy-table-item-label" style="width: 200px">
<span v-if="contract_category && contract_category.required_is_end === 1" style="color: red;font-weight: 600;padding-right: 4px;">*</span>
</div>
@ -245,7 +245,7 @@
</template>
<template v-slot:end_time>
<div v-if="contract_category && contract_category.show_end_time === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 2))" class="xy-table-item">
<div v-if="contract_category && contract_category.show_end_time === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1))" class="xy-table-item">
<div class="xy-table-item-label">项目完成时间</div>
<div class="xy-table-item-content">
<el-date-picker v-model="paymentRegistrationForm.end_time" type="date" value-format="yyyy-MM-dd HH:mm:ss" style="width: 150px;" />
@ -254,7 +254,7 @@
</template>
<template v-slot:isCheck>
<div v-if="contract_category && contract_category.show_check === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 2))" class="xy-table-item">
<div v-if="contract_category && contract_category.show_check === 1 && (!hasPostPaymentForm || (hasPostPaymentForm && currentStep === 1))" class="xy-table-item">
<div class="xy-table-item-label" style="width: 200px">
<span style="color: red;font-weight: 600;padding-right: 4px;" />是否验收
</div>
@ -265,7 +265,7 @@
</template>
<template v-slot:extraFormBottom>
<div v-if="hasPostPaymentForm && currentStep === 1" class="payment-table-section">
<div v-if="hasPostPaymentForm && currentStep === 2" class="payment-table-section">
<div class="section-header">
<div class="section-title">
事后支付表格
@ -299,7 +299,7 @@
<template v-slot:footerContent>
<div class="dialog-footer">
<el-button v-if="hasPostPaymentForm && currentStep === 2" @click="currentStep = 1"></el-button>
<el-button v-if="hasPostPaymentForm && currentStep === 2" @click="prevStep"></el-button>
<el-button v-if="hasPostPaymentForm && currentStep === 1" @click="nextStep"></el-button>
<el-button v-if="(hasPostPaymentForm && currentStep === 2) || (!hasPostPaymentForm)" type="primary" @click="submit"></el-button>
<el-button @click="resetForm"></el-button>
@ -464,70 +464,12 @@ import {
Message
} from 'element-ui'
import {
parseTime
parseTime,
numberToChinese
} from '@/utils'
import { getContractTemplateContext } from '@/api/businessConfig/businessConfig'
import { replaceControls } from './printPaymentForm.vue'
//
function numberToChinese(num) {
// 0""
if (num === 0) {
return '零元'
}
const units = ['', '拾', '佰', '仟', '万', '拾', '佰', '仟', '亿', '拾', '佰', '仟', '万']
const digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
const [integer, decimal] = num.toString().split('.')
let result = ''
let intNum = parseInt(integer)
if (intNum === 0) {
result = '零'
} else {
let i = 0
let lastDigit = null
let hasZero = false
while (intNum > 0) {
const digit = intNum % 10
if (digit === 0) {
if (!hasZero && lastDigit !== 0) {
result = '零' + result
hasZero = true
}
} else {
let unit = units[i]
if (i === 4 && result.startsWith('零')) {
unit = '万'
} else if (i === 8 && result.startsWith('零')) {
unit = '亿'
}
result = digits[digit] + unit + result
hasZero = false
}
lastDigit = digit
intNum = Math.floor(intNum / 10)
i++
}
result = result.replace(/零+$/, '')
result = result.replace(/零+/, '零')
}
if (decimal) {
const decimalNum = parseInt(decimal)
if (decimalNum > 0) {
result += '点'
for (let i = 0; i < decimal.length; i++) {
result += digits[parseInt(decimal[i])]
}
}
}
if (!decimal || parseInt(decimal) === 0) {
result += '整'
}
return result + '元'
}
// DOMHTML
function syncFormDomToHtml(dom, contractTemplateFields) {
if (!dom) return ''
@ -1080,14 +1022,7 @@ export default {
})
}
// amount
this.$nextTick(() => {
//
this.setupAmountListeners(this.$refs.mainTable1)
this.setupAmountListeners(this.$refs.mainTable2)
//
this.setupAmountListeners(this.$refs.zoomedTable)
})
//
},
// tab
@ -1362,72 +1297,55 @@ export default {
},
nextStep() {
try {
// .
let applyMoney = 0
if (this.total > 0) {
applyMoney = this.total
} else if (this.otherTotal > 0) {
applyMoney = this.otherTotal
}
//
let currentDom = null
if (this.activePostPaymentTab === 'form1') {
currentDom = this.$refs.mainTable1
} else if (this.activePostPaymentTab === 'form2') {
currentDom = this.$refs.mainTable2
}
if (currentDom) {
const currentPaymentInput = currentDom.querySelector('input[data-field="currentDuePayment"]')
if (currentPaymentInput) {
const inputValue = currentPaymentInput.value
if (inputValue && Number(inputValue) > 0) {
applyMoney = Number(inputValue)
}
}
}
this.paymentRegistrationForm.applyMoney = applyMoney
// currentStep=2
if (this.hasPostPaymentForm) {
// HTML openZoomedTable
let currentDom = null
if (this.activePostPaymentTab === 'form1') {
currentDom = this.$refs.mainTable1
} else if (this.activePostPaymentTab === 'form2') {
currentDom = this.$refs.mainTable2
}
if (currentDom && this.contract.contract_template) {
const updatedForms = syncFormDomToHtml(currentDom, this.contract.contract_template.contract_template_fields)
//
if (this.activePostPaymentTab === 'form1') {
this.forms1 = updatedForms
this.forms = this.forms1
} else if (this.activePostPaymentTab === 'form2') {
this.forms2 = updatedForms
this.forms = this.forms2
}
this.contract.forms = this.forms
}
this.currentStep = 2
} else {
// submit
if (this.$refs['paymentRegistration'] && this.$refs['paymentRegistration'].$refs['elForm']) {
this.$refs['paymentRegistration'].$refs['elForm'].validate().then(res => {
if (res) {
this.submit()
}
}).catch(err => {
console.error('表单验证失败:', err)
this.$Message.warning({
content: '请填写完整信息',
duration: 1
//
if (this.currentStep === 1) {
//
if (this.hasPostPaymentForm) {
//
if (this.$refs['paymentRegistration'] && this.$refs['paymentRegistration'].$refs['elForm']) {
this.$refs['paymentRegistration'].$refs['elForm'].validate().then(res => {
if (res) {
//
this.currentStep = 2
// amount
this.$nextTick(() => {
this.setupAmountListeners(this.$refs.mainTable1)
this.setupAmountListeners(this.$refs.mainTable2)
})
}
}).catch(err => {
console.error('表单验证失败:', err)
this.$Message.warning({
content: '请填写完整信息',
duration: 1
})
})
})
} else {
//
this.currentStep = 2
// amount
this.$nextTick(() => {
this.setupAmountListeners(this.$refs.mainTable1)
this.setupAmountListeners(this.$refs.mainTable2)
})
}
} else {
this.submit()
// submit
if (this.$refs['paymentRegistration'] && this.$refs['paymentRegistration'].$refs['elForm']) {
this.$refs['paymentRegistration'].$refs['elForm'].validate().then(res => {
if (res) {
this.submit()
}
}).catch(err => {
console.error('表单验证失败:', err)
this.$Message.warning({
content: '请填写完整信息',
duration: 1
})
})
} else {
this.submit()
}
}
}
} catch (error) {
@ -1439,6 +1357,13 @@ export default {
}
},
prevStep() {
//
if (this.currentStep === 2) {
this.currentStep = 1
}
},
resetForm() {
this.currentStep = 1
this.$refs['paymentRegistration'].reset()

@ -76,63 +76,7 @@
import { detailFundLog } from '@/api/paymentRegistration/fundLog'
import html2canvas from 'html2canvas'
import * as printJS from 'print-js'
//
function numberToChinese(num) {
if (num === 0) {
return '零元'
}
const units = ['', '拾', '佰', '仟', '万', '拾', '佰', '仟', '亿', '拾', '佰', '仟', '万']
const digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
const [integer, decimal] = num.toString().split('.')
let result = ''
let intNum = parseInt(integer)
if (intNum === 0) {
result = '零'
} else {
let i = 0
let lastDigit = null
let hasZero = false
while (intNum > 0) {
const digit = intNum % 10
if (digit === 0) {
if (!hasZero && lastDigit !== 0) {
result = '零' + result
hasZero = true
}
} else {
let unit = units[i]
if (i === 4 && result.startsWith('零')) {
unit = '万'
} else if (i === 8 && result.startsWith('零')) {
unit = '亿'
}
result = digits[digit] + unit + result
hasZero = false
}
lastDigit = digit
intNum = Math.floor(intNum / 10)
i++
}
result = result.replace(/零+$/, '')
result = result.replace(/零+/, '零')
}
if (decimal) {
const decimalNum = parseInt(decimal)
if (decimalNum > 0) {
result += '点'
for (let i = 0; i < decimal.length; i++) {
result += digits[parseInt(decimal[i])]
}
}
}
if (!decimal || parseInt(decimal) === 0) {
result += '整'
}
return result + '元'
}
import { numberToChinese } from '@/utils'
export default {
name: 'PrintPaymentForm',
@ -146,10 +90,10 @@ export default {
},
computed: {
getBeforeForms() {
return this.fundLog && this.fundLog.contract && this.fundLog.contract.before_forms
return this.fundLog && this.fundLog.before_forms
},
getForms() {
return this.fundLog && this.fundLog.contract && this.fundLog.contract.forms
return this.fundLog && this.fundLog.forms
}
},
watch: {
@ -770,7 +714,6 @@ export default {
return Number(val).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
},
printHtml() {
console.log('printHtml',this.fundLog)
// HTML
const dom = this.$refs.printtable
if (dom) {

Loading…
Cancel
Save