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.

464 lines
14 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 class="container">
<!-- 查询配置 -->
<div>
<div ref="lxHeader">
<LxHeader :custom="true" icon="el-icon-s-order" text="执行科室预算分解表提交" style="margin-bottom: 10px; border: 0px;">
<div>
<div class="search-panel">
<div class="filters">
<el-select
v-model="searchFields.year_id"
placeholder="选择预算年度"
style="width: 150px"
@change="load"
>
<el-option
v-for="item in yearOptions"
:key="item.value"
:label="item.year + '年'"
:value="item.value"
/>
</el-select>
<el-select
v-model="searchFields.status"
placeholder="选择状态"
style="width: 150px"
@change="load"
clearable
>
<el-option label="待提交" value="pending" />
<el-option label="已提交" value="submitted" />
<el-option label="已审核" value="reviewed" />
</el-select>
</div>
<div class="actions">
<Button type="primary" @click="load">查询</Button>
</div>
</div>
</div>
</LxHeader>
</div>
<!-- 分配给本科室的预算包列表 -->
<el-table
ref="packageTable"
:data="packageData"
:height="tableHeight"
class="v-table"
style="width: 100%; margin-bottom: 20px;"
border
v-loading="loading"
row-key="id"
>
<el-table-column type="index" align="center" label="序号" width="60" />
<el-table-column prop="budget_year" label="预算年度" width="100" align="center">
<template slot-scope="scope">
<el-tag type="primary">
{{ scope.row.budget_year ? scope.row.budget_year.year + '年' : '-' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="parent_name" label="上级包名称" min-width="200">
<template slot-scope="scope">
<span style="color: #909399; font-size: 12px;">
{{ scope.row.top_name || '-' }} - {{ scope.row.parent_name || '-' }}
</span>
</template>
</el-table-column>
<el-table-column prop="executing_department" label="执行部门" min-width="150">
<template slot-scope="scope">
<span style="color: #606266; font-size: 13px;">
{{ scope.row.department.name || '-' }}
</span>
</template>
</el-table-column>
<el-table-column prop="allocated_amount" label="分配金额" width="160" align="right">
<template slot-scope="scope">
<span style="color: #409EFF; font-weight: bold;">
{{ formatCurrency(scope.row.allocated_amount) }} 万元
</span>
</template>
</el-table-column>
<el-table-column prop="submitted_amount" label="提交金额" width="160" align="right">
<template slot-scope="scope">
<span style="color: #67C23A; font-weight: bold;">
{{ formatCurrency(scope.row.submission ? scope.row.submission.total_amount : 0) }} 万元
</span>
</template>
</el-table-column>
<el-table-column prop="submission_status" label="提交状态" width="120" align="center">
<template slot-scope="scope">
<el-tag :type="getStatusTagType(scope.row.submission_status)">
{{ getStatusText(scope.row.submission_status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="submission_date" label="提交时间" width="180" align="center">
<template slot-scope="scope">
{{ scope.row.submission_date ? formatDate(scope.row.submission_date) : '-' }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="200">
<template slot-scope="scope">
<Button
v-if="!scope.row.submission"
type="primary"
@click="openSubmissionForm(scope.row)"
size="small"
style="margin-right: 5px;"
>
填写分解表
</Button>
<Button
v-if="scope.row.submission"
type="warning"
@click="editSubmissionForm(scope.row)"
size="small"
style="margin-right: 5px;"
>
修改分解表
</Button>
<Button
v-if="scope.row.submission"
type="info"
@click="viewSubmissionForm(scope.row)"
size="small"
>
查看详情
</Button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分解表填写对话框 -->
<el-dialog
:title="dialogTitle"
:visible.sync="submissionDialogVisible"
width="95%"
:close-on-click-modal="false"
top="5vh"
custom-class="submission-dialog"
>
<budget-submission-form
v-if="submissionDialogVisible"
:package-data="currentPackage"
:mode="submissionMode"
@submit="handleSubmissionSubmit"
@cancel="submissionDialogVisible = false"
/>
</el-dialog>
</div>
</template>
<script>
import LxHeader from '@/components/LxHeader/index.vue'
import { getBudgetCollectionYearOptions } from '@/api/budget/budgetCollectionYear.js'
import { getDepartmentPackages, submitBudgetDecomposition } from '@/api/budget/departmentSubmission.js'
import BudgetSubmissionForm from './components/BudgetSubmissionForm.vue'
export default {
name: 'DepartmentSubmission',
components: {
LxHeader,
BudgetSubmissionForm
},
data() {
return {
loading: false,
tableHeight: 0,
searchFields: {
year_id: '',
status: ''
},
packageData: [],
yearOptions: [],
submissionDialogVisible: false,
currentPackage: null,
submissionMode: 'create' // create, edit, view
}
},
computed: {
dialogTitle() {
const titles = {
create: '填写预算分解表',
edit: '修改预算分解表',
view: '查看预算分解表'
}
return titles[this.submissionMode] || '预算分解表'
}
},
created() {
this.initLoad()
this.loadYearOptions()
},
methods: {
initLoad() {
const clientHeight = document.documentElement.clientHeight
const lxHeaderHeight = 140
const paginationHeight = 60
const topHeight = 50
const tableHeight = clientHeight - lxHeaderHeight - topHeight - paginationHeight - 20
this.tableHeight = tableHeight
},
async loadYearOptions() {
try {
const response = await getBudgetCollectionYearOptions()
console.log('年度选项接口响应:', response)
if (response) {
let yearData = response
// 如果data是字符串尝试解析JSON
if (typeof yearData === 'string') {
try {
yearData = JSON.parse(yearData)
} catch (e) {
console.error('解析年度选项JSON失败:', e)
this.$message.error('年度选项数据格式错误')
return
}
}
if (Array.isArray(yearData)) {
this.yearOptions = yearData
console.log('年度选项加载成功:', this.yearOptions)
// 默认选择第一个年度
if (this.yearOptions.length > 0 && !this.searchFields.year_id) {
this.searchFields.year_id = this.yearOptions[0].value
this.$nextTick(() => {
this.load()
})
} else if (this.yearOptions.length === 0) {
this.$message.warning('未找到可用的预算年度,请联系管理员')
}
} else {
console.warn('年度选项数据不是数组格式:', yearData)
this.$message.error('年度选项数据格式错误')
}
} else {
console.warn('年度选项接口响应异常:', response)
this.$message.error('年度选项接口返回格式错误')
}
} catch (error) {
console.error('加载年度选项失败:', error)
this.$message.error('加载年度选项失败,请刷新页面重试')
}
},
async load() {
if (!this.searchFields.year_id) {
this.$message.warning('请选择预算年度')
this.packageData = []
return
}
this.loading = true
try {
const params = {
...this.searchFields
}
const response = await getDepartmentPackages(params)
// 根据后端ApiResponse设计判断code为0表示成功
if (response) {
this.packageData = Array.isArray(response) ? response : []
} else {
this.packageData = []
this.$message.warning(response.msg || '获取预算包列表失败')
}
} catch (error) {
console.error('获取数据失败:', error)
if (error.response && error.response.data) {
const errorMessage = error.response.data.message || error.response.data.error || '获取数据失败'
this.$message.error(errorMessage)
} else {
this.$message.error('获取数据失败,请检查网络连接')
}
this.packageData = []
} finally {
this.loading = false
}
},
openSubmissionForm(packageItem) {
this.currentPackage = { ...packageItem }
this.submissionMode = 'create'
this.submissionDialogVisible = true
// 增加console.log输出当前表单数据
console.log('表单数据:', this.currentPackage)
},
editSubmissionForm(packageItem) {
this.currentPackage = { ...packageItem }
this.submissionMode = 'edit'
this.submissionDialogVisible = true
// 增加console.log输出当前表单数据
console.log('编辑表单数据:', this.currentPackage)
},
viewSubmissionForm(packageItem) {
this.currentPackage = { ...packageItem }
this.submissionMode = 'view'
this.submissionDialogVisible = true
},
async handleSubmissionSubmit(submissionData) {
try {
const response = await submitBudgetDecomposition(submissionData)
if (response && response.id) {
this.$message.success('提交成功')
this.submissionDialogVisible = false
this.load() // 重新加载数据
} else {
this.$message.error(response.msg || '提交失败')
}
} catch (error) {
console.error('提交失败:', error)
if (error.response && error.response.data && error.response.data.message) {
this.$message.error(error.response.data.message)
} else {
this.$message.error('提交失败')
}
}
},
formatCurrency(amount) {
if (amount === null || amount === undefined || amount === '') return '0.0'
const num = Number(amount)
return isFinite(num)
? num.toLocaleString('zh-CN', { minimumFractionDigits: 0, maximumFractionDigits: 0 })
: '0.0'
},
formatDate(dateStr) {
if (!dateStr) return '-'
const date = new Date(dateStr)
return date.toLocaleDateString('zh-CN') + ' ' + date.toLocaleTimeString('zh-CN', {
hour12: false,
hour: '2-digit',
minute: '2-digit'
})
},
getStatusTagType(status) {
const typeMap = {
pending: 'warning',
submitted: 'primary',
reviewed: 'success'
}
return typeMap[status] || 'info'
},
getStatusText(status) {
const textMap = {
pending: '待提交',
submitted: '已提交',
reviewed: '已审核'
}
return textMap[status] || '未知'
}
}
}
</script>
<style scoped>
.container {
padding: 12px 16px 16px 16px;
}
.v-table {
border: 1px solid #e6e6e6;
}
.search-panel {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 12px;
background: #fff;
border: 1px solid #ebeef5;
border-radius: 0;
}
.filters {
display: flex;
align-items: center;
gap: 12px;
}
.actions {
display: flex;
align-items: center;
gap: 10px;
}
/* 统一表格行高 */
.v-table >>> .el-table__body tr {
height: 50px !important;
}
.v-table >>> .el-table__body tr td {
height: 50px !important;
max-height: 50px !important;
vertical-align: middle !important;
padding: 8px 12px !important;
box-sizing: border-box !important;
}
/* 所有单元格内容的统一处理 */
.v-table >>> .el-table__body tr td .cell {
height: 34px !important;
max-height: 34px !important;
line-height: 18px !important;
overflow: hidden !important;
display: flex !important;
align-items: center !important;
}
/* 确保标签和按钮不会撑开行高 */
.v-table >>> .el-table__body tr td .el-tag {
height: 24px !important;
line-height: 22px !important;
}
.v-table >>> .el-table__body tr td .el-button {
height: 28px !important;
padding: 4px 8px !important;
}
</style>
<style>
/* 分解表对话框样式 */
.submission-dialog {
margin-top: 5vh !important;
}
.submission-dialog .el-dialog__body {
padding: 10px 20px !important;
max-height: 80vh;
overflow-y: auto;
}
</style>