-
- 事后支付表格
-
- 放大查看
+
@@ -227,6 +301,122 @@
>
+
+
+
+
+
+
+
+
+ {{ priceFormat(scope.row.apply_money) }}
+
+
+
+
+ {{ priceFormat(scope.row.act_money) }}
+
+
+
+
+
+ {{ scope.row.is_end === 1 ? '是' : '否' }}
+
+
+
+
+ {{ parseTime(new Date(scope.row.created_at)) }}
+
+
+
+
+
+ 查看
+
+
+
+
+
+
+
+
+
+
+
+ 暂无数据
+
@@ -243,7 +433,8 @@ import {
} from '@/api/budget/budget'
import {
detailContract,
- editorContract
+ editorContract,
+ getContractList
} from '@/api/contract/contract'
import {
Message
@@ -252,6 +443,7 @@ import {
parseTime
} from '@/utils'
import { getContractTemplateContext } from '@/api/businessConfig/businessConfig'
+import { replaceControls } from './printPaymentForm.vue'
// 添加金额转大写的工具函数
function numberToChinese(num) {
@@ -344,29 +536,68 @@ export default {
payment: [], // 合同关联的付款登记
contractTemplate: null, // 合同模板HTML
forms: null, // 实际表单HTML
- 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}')
+ payTable: [
+ {
+ label: '款项类型',
+ prop: 'type',
+ width: 120
+ },
+ {
+ label: '申请金额',
+ prop: 'apply_money',
+ width: 150,
+ formatter: (row) => {
+ return this.priceFormat(row.apply_money)
+ }
+ },
+ {
+ label: '已付金额',
+ prop: 'act_money',
+ width: 150,
+ formatter: (row) => {
+ return this.priceFormat(row.act_money)
+ }
+ },
+ {
+ label: '是否最后一笔',
+ prop: 'is_end',
+ width: 120,
+ formatter: (row) => {
+ return row.is_end === 1 ? '是' : '否'
+ }
+ },
+ {
+ label: '备注',
+ prop: 'remark',
+ width: 100
+ },
+ {
+ label: '创建时间',
+ prop: 'created_at',
+ width: 180,
+ formatter: (row) => {
+ return parseTime(new Date(row.created_at))
+ }
+ },
+ {
+ label: '事后支付表格',
+ width: 120,
+ render: (h, params) => {
+ return h('div', [
+ h('el-button', {
+ props: {
+ type: 'text',
+ size: 'small'
+ },
+ on: {
+ click: () => {
+ this.showPostPaymentForm(params.row)
+ }
+ }
+ }, '查看')
+ ])
+ }
}
- }
],
paymentType: ['预付款', '进度款', '结算款', '质保金'],
isShowPaymentRegistration: false,
@@ -468,7 +699,77 @@ export default {
contract_category: {},
templateContextData: null, // 合同模板关联数据
total: 0,
- otherTotal: 0
+ otherTotal: 0,
+ historyDialogVisible: false,
+ historyActiveTab: 'same',
+ sameContractHistoryList: [],
+ similarContractHistoryList: [],
+ historyTable: [
+ {
+ label: '申请金额',
+ prop: 'apply_money',
+ width: 150,
+ formatter: (row) => {
+ return this.priceFormat(row.apply_money)
+ }
+ },
+ {
+ label: '已付金额',
+ prop: 'act_money',
+ width: 150,
+ formatter: (row) => {
+ return this.priceFormat(row.act_money)
+ }
+ },
+ {
+ label: '款项类型',
+ prop: 'type',
+ width: 120
+ },
+ {
+ label: '是否最后一笔',
+ prop: 'is_end',
+ width: 120,
+ formatter: (row) => {
+ return row.is_end === 1 ? '是' : '否'
+ }
+ },
+ {
+ label: '创建时间',
+ prop: 'created_at',
+ width: 180,
+ formatter: (row) => {
+ return parseTime(new Date(row.created_at))
+ }
+ },
+ {
+ label: '事后支付表格',
+ prop: 'post_payment_form',
+ width: 120,
+ render: (h, params) => {
+ return h('div', [
+ h('el-button', {
+ props: {
+ type: 'text',
+ size: 'small'
+ },
+ on: {
+ click: () => {
+ this.showPostPaymentForm(params.row)
+ }
+ }
+ }, '查看')
+ ])
+ }
+ }
+ ],
+ postPaymentFormDialogVisible: false,
+ currentPostPaymentForm: null,
+ historyPagination: {
+ page: 1,
+ pageSize: 20,
+ total: 0
+ }
}
},
computed: {
@@ -1357,6 +1658,189 @@ export default {
wanTotal = parseFloat(wanInput.value) || 0
upperCaseInput.value = numberToChinese(wanTotal)
}
+ },
+
+ // 显示历史记录弹窗
+ async showHistoryDialog() {
+ this.historyDialogVisible = true
+ this.historyActiveTab = 'same'
+ await this.fetchHistoryData()
+ },
+
+ // 处理 tab 切换
+ async handleHistoryTabClick() {
+ await this.fetchHistoryData()
+ },
+
+ // 获取历史记录数据
+ async fetchHistoryData() {
+ try {
+ if (this.historyActiveTab === 'same') {
+ // 获取同一合同的付款记录
+ const res = await getFundLog({
+ contract_category: this.contract.contract_category.category,
+ work_type: this.contract.contract_category.work_type,
+ contract_type: this.contract.contract_category.contract_type,
+ purchase_form: this.contract.contract_category.purchase_form,
+ page: this.historyPagination.page,
+ page_size: this.historyPagination.pageSize
+ })
+ this.sameContractHistoryList = res.data
+ this.historyPagination.total = res.total || 0
+ } else {
+ // 获取同类合同的付款记录
+ const res = await getFundLog({
+ contract_category_id: this.contract.contract_category_id,
+ page: this.historyPagination.page,
+ page_size: this.historyPagination.pageSize,
+ exclude_contract_id: this.contract.id // 排除当前合同
+ })
+ this.similarContractHistoryList = res.data
+ this.historyPagination.total = res.total || 0
+ }
+ } catch (error) {
+ console.error('获取历史记录失败:', error)
+ this.$Message.error('获取历史记录失败')
+ }
+ },
+
+ // 处理每页显示数量变化
+ handleHistorySizeChange(val) {
+ this.historyPagination.pageSize = val
+ this.historyPagination.page = 1
+ this.fetchHistoryData()
+ },
+
+ // 处理页码变化
+ handleHistoryCurrentChange(val) {
+ this.historyPagination.page = val
+ this.fetchHistoryData()
+ },
+
+ // 显示事后支付表格
+ showPostPaymentForm(row) {
+ // 创建一个临时的 div 来处理 forms 内容
+ const tempDiv = document.createElement('div')
+ tempDiv.innerHTML = row.forms
+ this.replaceControls(tempDiv)
+ this.currentPostPaymentForm = tempDiv.innerHTML
+ this.postPaymentFormDialogVisible = true
+ },
+ parseTime(time) {
+ if (!time) return ''
+ return parseTime(time)
+ },
+ replaceControls(element) {
+ const inputs = element.getElementsByTagName('input')
+ Array.from(inputs).forEach(input => {
+ if (input.type === 'checkbox' || input.type === 'radio') {
+ if (input.type === 'radio') {
+ const name = input.name
+ const checkedRadio = element.querySelector(`input[type="radio"][name="${name}"]:checked`)
+ if (checkedRadio) {
+ const td = checkedRadio.closest('td')
+ if (td) {
+ const hiddenDiv = td.querySelector('div[style*="display: none"]')
+ if (hiddenDiv) {
+ hiddenDiv.textContent = checkedRadio.value
+ }
+ }
+ }
+ }
+ return
+ }
+ const span = document.createElement('span')
+ let displayText = input.value || ''
+ if (input.type === 'date') {
+ displayText = input.value ? new Date(input.value).toLocaleDateString() : ''
+ }
+ span.textContent = displayText
+ const style = window.getComputedStyle(input)
+ span.style.cssText = style.cssText
+ ;[
+ 'width',
+ 'height',
+ 'padding',
+ 'margin',
+ 'font',
+ 'fontSize',
+ 'fontFamily',
+ 'lineHeight',
+ 'verticalAlign',
+ 'border',
+ 'background',
+ 'color',
+ 'boxSizing'
+ ].forEach(key => {
+ span.style[key] = style[key]
+ })
+ span.style.whiteSpace = 'normal'
+ span.style.wordBreak = 'break-all'
+ span.style.overflowWrap = 'break-word'
+ span.style.display = 'block'
+ span.style.width = '100%'
+ input.parentNode.replaceChild(span, input)
+ })
+
+ const selects = element.getElementsByTagName('select')
+ Array.from(selects).forEach(select => {
+ const span = document.createElement('span')
+ span.textContent = select.options[select.selectedIndex]?.text || ''
+ const style = window.getComputedStyle(select)
+ span.style.cssText = style.cssText
+ ;[
+ 'width',
+ 'height',
+ 'padding',
+ 'margin',
+ 'font',
+ 'fontSize',
+ 'fontFamily',
+ 'lineHeight',
+ 'verticalAlign',
+ 'border',
+ 'background',
+ 'color',
+ 'boxSizing'
+ ].forEach(key => {
+ span.style[key] = style[key]
+ })
+ span.style.width = '100%'
+ span.style.display = 'block'
+ span.style.textAlign = 'center'
+ span.style.whiteSpace = 'pre-line'
+ select.parentNode.replaceChild(span, select)
+ })
+
+ const textareas = element.getElementsByTagName('textarea')
+ Array.from(textareas).forEach(textarea => {
+ const span = document.createElement('span')
+ span.textContent = textarea.value || ''
+ const style = window.getComputedStyle(textarea)
+ span.style.cssText = style.cssText
+ ;[
+ 'width',
+ 'height',
+ 'padding',
+ 'margin',
+ 'font',
+ 'fontSize',
+ 'fontFamily',
+ 'lineHeight',
+ 'verticalAlign',
+ 'border',
+ 'background',
+ 'color',
+ 'boxSizing'
+ ].forEach(key => {
+ span.style[key] = style[key]
+ })
+ span.style.width = '100%'
+ span.style.display = 'block'
+ span.style.textAlign = 'center'
+ span.style.whiteSpace = 'pre-line'
+ textarea.parentNode.replaceChild(span, textarea)
+ })
}
}
}
@@ -1380,10 +1864,16 @@ export default {
margin-top: 20px;
padding: 0 20px;
+ .section-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 10px;
+ }
+
.section-title {
font-size: 14px;
font-weight: bold;
- margin-bottom: 10px;
color: #333;
display: flex;
align-items: center;
@@ -1474,5 +1964,67 @@ export default {
align-items: center;
justify-content: center;
}
+
+ .history-dialog {
+ .el-dialog__body {
+ padding: 20px;
+ }
+
+ .history-table-container {
+ height: 500px;
+ overflow: hidden;
+ }
+
+ .pagination-container {
+ margin-top: 20px;
+ text-align: right;
+ }
+ }
+
+ .history-filter {
+ margin-bottom: 20px;
+ padding: 0 20px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border-bottom: 1px solid #EBEEF5;
+ padding-bottom: 15px;
+ }
+
+ .history-dialog {
+ ::v-deep .el-dialog__body {
+ padding: 20px 30px;
+ }
+ }
+
+ .pagination-container {
+ margin-top: 20px;
+ display: flex;
+ justify-content: flex-end;
+ }
+
+ .table-container {
+ position: relative;
+ width: 100%;
+ height: 200px;
+ overflow: hidden;
+ }
+
+ .post-payment-dialog {
+ display: flex;
+ flex-direction: column;
+ max-height: 80vh;
+
+ ::v-deep .el-dialog__body {
+ flex: 1;
+ overflow-y: auto;
+ padding: 10px 20px;
+ }
+ }
+
+ .post-payment-content {
+ max-height: calc(80vh - 120px);
+ overflow-y: auto;
+ }