预算填报模块迭代

master
weizong song 1 week ago
parent 3082e3ac30
commit 4395c4b225

@ -114,6 +114,14 @@ export function reviewDepartmentSubmission(submissionId, data) {
})
}
export function reviewDepartmentSubmissionByManager(submissionId, data) {
return request({
url: `/api/admin/department-submissions/${submissionId}/manager-review`,
method: 'post',
data
})
}
export function getDepartmentSubmissions(params = {}) {
return request({
url: '/api/admin/department-submissions',
@ -122,6 +130,14 @@ export function getDepartmentSubmissions(params = {}) {
})
}
export function getManagerReviewDepartmentSubmissions(params = {}) {
return request({
url: '/api/admin/department-submissions/manager-review-list',
method: 'get',
params
})
}
/**
* 编辑第二层预算包包含子项管理
* @param {Number} id 预算包ID

@ -119,12 +119,23 @@ export const constantRoutes = [
icon: 's-order'
}
},
{
path: 'manager-review',
name: 'DepartmentManagerReview',
component: () => import('@/views/budget/departmentReview/index'),
props: { reviewStage: 'manager' },
meta: {
title: '科室负责人审核',
icon: 's-check'
}
},
{
path: 'department-review',
name: 'DepartmentReview',
component: () => import('@/views/budget/departmentReview/index'),
props: { reviewStage: 'leader' },
meta: {
title: '执行科室分解审核',
title: '分管领导审核',
icon: 's-check'
}
}

@ -1134,7 +1134,7 @@ export default {
? this.packageData.submission.status
: this.packageData.submission_status
return !this.isViewMode && !(this.mode === 'edit' && currentStatus === 'submitted')
return !this.isViewMode && !(this.mode === 'edit' && currentStatus !== 'draft')
},
allocatedAmountNum() {

@ -0,0 +1,27 @@
<template>
<div v-loading="loading" class="summary-detail">
<template v-if="summary">
<section class="section">
<h3>基本信息</h3>
<el-row :gutter="20"><el-col :span="8"><p><b>牵头科室</b>{{ packageData.department && packageData.department.name || '-' }}</p></el-col><el-col :span="8"><p><b></b>{{ packageData.budget_year && packageData.budget_year.year }}</p></el-col><el-col :span="8"><p><b></b>{{ money(packageData.allocated_amount) }} </p></el-col><el-col :span="24"><p><b></b>{{ packageData.name || '-' }}</p></el-col></el-row>
</section>
<section class="section"><h3>汇总申请信息</h3><el-row :gutter="20"><el-col v-for="item in applicationItems" :key="item.label" :span="12"><div class="field"><b>{{ item.label }}</b><pre>{{ item.value || '-' }}</pre></div></el-col></el-row></section>
<section class="section"><h3>经济分类汇总</h3><el-table :data="summary.economicSummary || []" border><el-table-column type="index" label="序号" width="60" align="center" /><el-table-column prop="categoryName" label="经济分类" min-width="180" /><el-table-column label="汇总金额(万元)" width="160" align="right"><template slot-scope="{ row }">{{ money(row.totalAmount) }}</template></el-table-column><el-table-column label="" min-width="300"><template slot-scope="{ row }"><pre>{{ row.summaryCalculationBasis || '-' }}</pre></template></el-table-column><el-table-column label="" min-width="220"><template slot-scope="{ row }"><file-links :files="row.files" /></template></el-table-column></el-table></section>
<section class="section"><h3>申请资金汇总</h3><el-table :data="[summary.fundApplication || {}]" border><el-table-column label="新项目总额"><template slot-scope="{ row }">{{ money(row.newProject && row.newProject.totalAmount) }}</template></el-table-column><el-table-column label=""><template slot-scope="{ row }">{{ money(row.newProject && row.newProject.yearCurrent) }}</template></el-table-column><el-table-column label=""><template slot-scope="{ row }">{{ money(row.newProject && row.newProject.yearNext) }}</template></el-table-column><el-table-column label=""><template slot-scope="{ row }">{{ money(row.oldProject && row.oldProject.contractTotal) }}</template></el-table-column><el-table-column label=""><template slot-scope="{ row }">{{ money(row.oldProject && row.oldProject.previousYearsTotal) }}</template></el-table-column><el-table-column label=""><template slot-scope="{ row }">{{ money(row.oldProject && row.oldProject.previousYearBalance) }}</template></el-table-column><el-table-column label=""><template slot-scope="{ row }">{{ money(row.oldProject && row.oldProject.yearCurrent) }}</template></el-table-column><el-table-column label="" min-width="160"><template slot-scope="{ row }">{{ row.oldProject && row.oldProject.contractNumber || '-' }}</template></el-table-column></el-table></section>
<section class="section"><h3>项目实施进度安排汇总</h3><div class="field"><b>实施进度安排</b><pre>{{ summary.implementationSchedule || '-' }}</pre></div><div class="field"><b>当年实施内容</b><pre>{{ schedule.currentYearContent || '-' }}</pre></div><el-table :data="[schedule]" border class="month-table"><el-table-column label="当年金额"><template slot-scope="{ row }">{{ money(row.currentYearAmount) }}</template></el-table-column><el-table-column v-for="month in 12" :key="month" :label="`${month}`"><template slot-scope="{ row }">{{ money(row[`currentYearMonth${month}`]) }}</template></el-table-column></el-table><el-row :gutter="20"><el-col :span="12"><div class="field"><b></b><pre>{{ schedule.nextYearContent || '-' }}</pre></div></el-col><el-col :span="12"><div class="field"><b></b><pre>{{ schedule.thirdYearContent || '-' }}</pre></div></el-col></el-row></section>
<section class="section"><h3>项目预计取得绩效汇总</h3><el-table :data="summary.summaryPerformanceIndicators || []" border><el-table-column prop="level1" label="一级指标" /><el-table-column prop="level2" label="二级指标" /><el-table-column prop="level3" label="三级指标" /><el-table-column prop="symbol" label="指标性质" width="110" /><el-table-column prop="halfYearValue" label="半年目标值" /><el-table-column prop="fullYearValue" label="全年目标值" /><el-table-column prop="unit" label="单位" width="100" /></el-table></section>
<section class="section"><h3>其他说明及附件</h3><div class="field"><b>其他说明</b><pre>{{ summary.otherNotes || '-' }}</pre></div><div class="field"><b>附件</b><file-links :files="summary.generalFiles" /></div></section>
</template>
<el-empty v-else-if="!loading" description="未找到该中包的汇总提交数据" />
</div>
</template>
<script>
import { getLeadDepartmentSummary } from '@/api/budget/leadDepartment'
const FileLinks = { props: { files: { type: Array, default: () => [] }}, methods: { open(file) { if (file.url) window.open(file.url, '_blank') } }, template: '<div v-if="files && files.length"><el-link v-for="(file, index) in files" :key="file.fileId || file.id || index" type="primary" :underline="false" @click="open(file)">{{ file.name || file.originalName || file.original_name || \'附件\' }}<br></el-link></div><span v-else>-</span>' }
export default { name: 'LeadDepartmentSummaryDetail', components: { FileLinks }, props: { packageData: { type: Object, required: true }}, data: () => ({ loading: true, summary: null }), computed: { schedule() { return this.summary && this.summary.implementationScheduleDetail || {} }, applicationItems() { return [{ label: '申请依据', value: this.summary.applicationBasis }, { label: '申请目的', value: this.summary.applicationPurpose }, { label: '申请理由', value: this.summary.applicationReason }, { label: '项目内容', value: this.summary.projectContent }] } }, async created() { try { const response = await getLeadDepartmentSummary(this.packageData.id); this.summary = response.data || response } catch (error) { this.$message.error(error.message || '加载中包汇总详情失败') } finally { this.loading = false } }, methods: { money(value) { const number = Number(value); return Number.isFinite(number) ? number.toFixed(4) : '0.0000' } }}
</script>
<style scoped>
.section { margin: 0 0 20px; padding: 18px 20px; border: 1px solid #ebeef5; border-radius: 4px; }.section h3 { margin: 0 0 16px; padding-bottom: 10px; color: #303133; border-bottom: 2px solid #409eff; font-size: 16px; }.section p { margin: 0 0 12px; }.field { margin-bottom: 14px; }.field b { display: block; margin-bottom: 7px; color: #606266; }pre { margin: 0; white-space: pre-wrap; word-break: break-word; font: inherit; color: #303133; }.month-table { margin: 12px 0; }
</style>

@ -1802,6 +1802,7 @@ export default {
const typeMap = {
pending: 'warning',
submitted: 'primary',
manager_approved: 'primary',
draft: 'warning',
approved: 'success'
}
@ -1811,9 +1812,10 @@ export default {
getStatusText(status) {
const textMap = {
pending: '待提交',
submitted: '已提交',
submitted: '待科室负责人审核',
manager_approved: '待分管领导审核',
draft: '已退回',
approved: '已确认'
approved: '终审通过'
}
return textMap[status] || '未知'
},

@ -200,6 +200,7 @@ export default {
const statusMap = {
'draft': 'info',
'submitted': 'warning',
'manager_approved': 'primary',
'approved': 'success',
'rejected': 'danger'
}
@ -212,8 +213,9 @@ export default {
const statusMap = {
'draft': '草稿',
'submitted': '已提交',
'approved': '已通过',
'submitted': '待科室负责人审核',
'manager_approved': '待分管领导审核',
'approved': '终审通过',
'rejected': '已拒绝'
}
return statusMap[submission.status] || '未知'

@ -30,8 +30,9 @@
>
<el-option label="待提交" value="pending" />
<el-option label="草稿/已退回" value="draft" />
<el-option label="已提交" value="submitted" />
<el-option label="审核通过" value="approved" />
<el-option label="待科室负责人审核" value="submitted" />
<el-option label="待分管领导审核" value="manager_approved" />
<el-option label="终审通过" value="approved" />
</el-select>
</div>
<div class="actions">
@ -123,7 +124,7 @@
</Button>
<Button
v-if="scope.row.submission && ['draft', 'submitted'].includes(scope.row.submission.status) && canWrite(scope.row)"
v-if="scope.row.submission && scope.row.submission.status === 'draft' && canWrite(scope.row)"
type="warning"
size="small"
@click="editSubmissionForm(scope.row)"
@ -329,7 +330,7 @@ export default {
},
async editSubmissionForm(packageItem) {
if (!packageItem.submission || !['draft', 'submitted'].includes(packageItem.submission.status) || !this.canWrite(packageItem)) {
if (!packageItem.submission || packageItem.submission.status !== 'draft' || !this.canWrite(packageItem)) {
this.$message.warning('当前申报状态不可修改')
return
}
@ -413,6 +414,7 @@ export default {
pending: 'warning',
draft: 'warning',
submitted: 'primary',
manager_approved: 'primary',
approved: 'success',
rejected: 'danger'
}
@ -423,8 +425,9 @@ export default {
const textMap = {
pending: '待提交',
draft: '草稿/已退回',
submitted: '已提交',
approved: '审核通过',
submitted: '待科室负责人审核',
manager_approved: '待分管领导审核',
approved: '终审通过',
rejected: '已拒绝'
}
return textMap[status] || '未知'
@ -447,6 +450,10 @@ export default {
const actionMap = {
submit: '提交审核',
resubmit: '重新提交',
manager_approve: '科室负责人初审通过',
manager_return: '科室负责人退回修改',
leader_approve: '分管领导终审通过',
leader_return: '分管领导退回修改',
approve: '审核通过',
return: '退回修改'
}

@ -118,8 +118,18 @@
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="200">
<el-table-column fixed="right" label="操作" width="280">
<template slot-scope="scope">
<Button
v-if="scope.row.level === 2 || scope.row.level === 3"
type="primary"
size="small"
style="margin-right: 5px;"
ghost
@click="viewPackageDetails(scope.row)"
>
查看详情
</Button>
<Button
v-if="scope.row.level <= 2"
type="info"
@ -240,8 +250,18 @@
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="200">
<el-table-column fixed="right" label="操作" width="280">
<template slot-scope="scope">
<Button
v-if="scope.row.level === 2 || scope.row.level === 3"
type="primary"
size="small"
style="margin-right: 5px;"
ghost
@click="viewPackageDetails(scope.row)"
>
查看详情
</Button>
<Button
v-if="scope.row.level <= 2"
type="info"
@ -540,6 +560,30 @@
</div>
</el-dialog>
<!-- 中包汇总填报小包预算分解表详情 -->
<el-dialog
:title="currentPackageDetail.level === 2 ? '查看汇总填报表' : '查看预算分解表'"
:visible.sync="packageDetailVisible"
width="96%"
top="3vh"
:close-on-click-modal="false"
@closed="currentPackageDetail = {}"
>
<div v-loading="packageDetailLoading" class="package-detail-content">
<lead-department-summary-detail
v-if="currentPackageDetail.id && currentPackageDetail.level === 2"
:package-data="currentPackageDetail"
/>
<budget-submission-form
v-else-if="currentPackageDetail.id && currentPackageDetail.level === 3"
:package-data="currentPackageDetail"
mode="view"
:show-application-info="true"
@cancel="packageDetailVisible = false"
/>
</div>
</el-dialog>
<!-- 编辑对话框 -->
<el-dialog :title="dialogTitle" :visible.sync="dialogFormVisible" width="60%">
<el-form
@ -672,8 +716,11 @@
<script>
import LxHeader from '@/components/LxHeader/index.vue'
import LeadDepartmentSummaryDetail from './components/LeadDepartmentSummaryDetail.vue'
import BudgetSubmissionForm from './components/BudgetSubmissionForm.vue'
import {
getBudgetCollectionPackageList,
getBudgetCollectionPackageDetail,
createBudgetCollectionPackage,
updateBudgetCollectionPackage,
deleteBudgetCollectionPackage,
@ -694,11 +741,16 @@ import {
export default {
name: 'BudgetCollectionPackage',
components: {
LxHeader
LxHeader,
LeadDepartmentSummaryDetail,
BudgetSubmissionForm
},
data() {
return {
dialogFormVisible: false,
packageDetailVisible: false,
packageDetailLoading: false,
currentPackageDetail: {},
formLabelWidth: '120px',
loading: false,
submitting: false,
@ -1045,6 +1097,24 @@ export default {
})
},
async viewPackageDetails(row) {
this.packageDetailVisible = true
this.packageDetailLoading = true
this.currentPackageDetail = { ...row }
try {
const response = await getBudgetCollectionPackageDetail(row.id)
const data = response && (response.data || response)
if (data && data.id) {
this.currentPackageDetail = data
}
} catch (error) {
this.$Message.error('加载预算包详情失败')
console.error('加载预算包详情失败:', error)
} finally {
this.packageDetailLoading = false
}
},
async addChild(parent) {
this.form = this.getDefaultForm()
this.form.year_id = parent.year_id
@ -2199,6 +2269,10 @@ export default {
text-align: right;
}
.package-detail-content {
min-height: 320px;
}
.el-tag {
margin-right: 5px;
}

@ -1,7 +1,7 @@
<template>
<div class="container">
<div ref="lxHeader">
<LxHeader :custom="true" icon="el-icon-s-check" text="执行科室分解审核" style="margin-bottom: 10px; border: 0;">
<LxHeader :custom="true" icon="el-icon-s-check" :text="pageTitle" style="margin-bottom: 10px; border: 0;">
<div>
<div class="search-panel">
<div class="filters">
@ -27,8 +27,9 @@
@change="load"
>
<el-option label="草稿" value="draft" />
<el-option label="已提交" value="submitted" />
<el-option label="审核通过" value="approved" />
<el-option label="待科室负责人审核" value="submitted" />
<el-option label="待分管领导审核" value="manager_approved" />
<el-option label="终审通过" value="approved" />
</el-select>
</div>
<div class="actions">
@ -111,7 +112,7 @@
<div class="action-group">
<el-button type="primary" size="mini" @click="viewDetail(scope.row)"></el-button>
<el-button
v-if="scope.row.status === 'submitted'"
v-if="scope.row.status === reviewableStatus"
type="warning"
size="mini"
@click="openReviewDialog(scope.row)"
@ -153,7 +154,7 @@
</el-dialog>
<el-dialog
title="执行科室分解审核"
:title="pageTitle"
:visible.sync="reviewDialogVisible"
width="96%"
:close-on-click-modal="false"
@ -262,7 +263,12 @@ import { formatMoney } from '@/utils/budgetMoney'
import LxHeader from '@/components/LxHeader/index.vue'
import BudgetSubmissionForm from '@/views/budget/collection/components/BudgetSubmissionForm.vue'
import { getBudgetCollectionYearOptions } from '@/api/budget/budgetCollectionYear.js'
import { getDepartmentSubmissions, reviewDepartmentSubmission } from '@/api/budget/leadDepartment.js'
import {
getDepartmentSubmissions,
getManagerReviewDepartmentSubmissions,
reviewDepartmentSubmission,
reviewDepartmentSubmissionByManager
} from '@/api/budget/leadDepartment.js'
export default {
name: 'DepartmentReviewManagement',
@ -270,6 +276,12 @@ export default {
LxHeader,
BudgetSubmissionForm
},
props: {
reviewStage: {
type: String,
default: 'leader'
}
},
data() {
return {
loading: false,
@ -296,6 +308,17 @@ export default {
}
}
},
computed: {
isManagerReview() {
return this.reviewStage === 'manager'
},
pageTitle() {
return this.isManagerReview ? '科室负责人审核' : '分管领导审核'
},
reviewableStatus() {
return this.isManagerReview ? 'submitted' : 'manager_approved'
}
},
created() {
this.initLoad()
this.loadYearOptions()
@ -339,7 +362,8 @@ export default {
this.loading = true
try {
const response = await getDepartmentSubmissions({
const getList = this.isManagerReview ? getManagerReviewDepartmentSubmissions : getDepartmentSubmissions
const response = await getList({
...this.searchFields,
page_size: this.pageSize,
page: this.currentPage
@ -350,7 +374,7 @@ export default {
this.currentPage = response ? response.current_page || 1 : 1
} catch (error) {
console.error('获取执行科室分解审核列表失败:', error)
this.$message.error(error.message || '获取执行科室分解审核列表失败')
this.$message.error(error.message || `获取${this.pageTitle}列表失败`)
this.tableData = []
this.total = 0
} finally {
@ -397,11 +421,14 @@ export default {
this.reviewSubmitting = true
try {
await reviewDepartmentSubmission(this.currentReviewRow.id, {
const review = this.isManagerReview ? reviewDepartmentSubmissionByManager : reviewDepartmentSubmission
await review(this.currentReviewRow.id, {
action: this.reviewForm.action,
approval_notes: this.reviewForm.approval_notes.trim()
})
this.$message.success(this.reviewForm.action === 'approve' ? '审核通过' : '已退回执行科室修改')
this.$message.success(this.reviewForm.action === 'approve'
? (this.isManagerReview ? '初审通过,已提交分管领导审核' : '终审通过')
: '已退回执行科室修改')
this.reviewDialogVisible = false
await this.load()
} catch (error) {
@ -460,6 +487,7 @@ export default {
const typeMap = {
draft: 'info',
submitted: 'warning',
manager_approved: 'primary',
approved: 'success'
}
return typeMap[status] || 'info'
@ -468,8 +496,9 @@ export default {
getStatusText(status) {
const textMap = {
draft: '草稿',
submitted: '已提交',
approved: '审核通过'
submitted: '待科室负责人审核',
manager_approved: '待分管领导审核',
approved: '终审通过'
}
return textMap[status] || '未知'
},
@ -484,6 +513,10 @@ export default {
const actionMap = {
submit: '提交审核',
resubmit: '重新提交',
manager_approve: '科室负责人初审通过',
manager_return: '科室负责人退回修改',
leader_approve: '分管领导终审通过',
leader_return: '分管领导退回修改',
approve: '审核通过',
return: '退回修改'
}

Loading…
Cancel
Save