|
|
|
|
@ -33,6 +33,7 @@
|
|
|
|
|
<Button type="primary" @click="load">查询</Button>
|
|
|
|
|
<Button type="primary" @click="edit()">新增预算包</Button>
|
|
|
|
|
<Button type="error" @click="batchDelete" :disabled="selectedRows.length === 0">批量删除</Button>
|
|
|
|
|
<Button type="warning" @click="recalculateYearAmounts">重算年度大包金额</Button>
|
|
|
|
|
<Button type="success" @click="toggleTreeView">{{ showTree ? '列表视图' : '树形视图' }}</Button>
|
|
|
|
|
<Button type="warning" @click="showSummaryView">汇总查看</Button>
|
|
|
|
|
</div>
|
|
|
|
|
@ -91,7 +92,13 @@
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
|
|
<el-table-column prop="allocated_amount" label="分配金额" width="120" align="right">
|
|
|
|
|
<el-table-column prop="sort_order" label="排序" width="80" align="center">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
{{ scope.row.sort_order || '-' }}
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
|
|
<el-table-column prop="allocated_amount" label="分配金额(大包自动汇总)" width="180" align="right">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
<span style="color: #409EFF; font-weight: bold;">
|
|
|
|
|
{{ formatCurrency(scope.row.allocated_amount) }} 万元
|
|
|
|
|
@ -149,15 +156,15 @@
|
|
|
|
|
>
|
|
|
|
|
删除
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
<Button
|
|
|
|
|
v-if="scope.row.level === 1"
|
|
|
|
|
type="warning"
|
|
|
|
|
@click="multiPackageSubmit(scope.row)"
|
|
|
|
|
type="warning"
|
|
|
|
|
@click="recalculatePackageAmount(scope.row)"
|
|
|
|
|
size="small"
|
|
|
|
|
style="margin-right: 5px;"
|
|
|
|
|
ghost
|
|
|
|
|
>
|
|
|
|
|
多包汇总提交
|
|
|
|
|
重新计算金额
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
type="primary"
|
|
|
|
|
@ -225,7 +232,13 @@
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
|
|
<el-table-column prop="allocated_amount" label="分配金额" width="120" align="right">
|
|
|
|
|
<el-table-column prop="sort_order" label="排序" width="80" align="center">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
{{ scope.row.sort_order || '-' }}
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
|
|
<el-table-column prop="allocated_amount" label="分配金额(大包自动汇总)" width="180" align="right">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
<span style="color: #409EFF; font-weight: bold;">
|
|
|
|
|
{{ formatCurrency(scope.row.allocated_amount) }} 万元
|
|
|
|
|
@ -289,15 +302,15 @@
|
|
|
|
|
>
|
|
|
|
|
删除
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
<Button
|
|
|
|
|
v-if="scope.row.level === 1"
|
|
|
|
|
type="warning"
|
|
|
|
|
@click="multiPackageSubmit(scope.row)"
|
|
|
|
|
type="warning"
|
|
|
|
|
@click="recalculatePackageAmount(scope.row)"
|
|
|
|
|
size="small"
|
|
|
|
|
style="margin-right: 5px;"
|
|
|
|
|
ghost
|
|
|
|
|
>
|
|
|
|
|
多包汇总提交
|
|
|
|
|
重新计算金额
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
type="primary"
|
|
|
|
|
@ -709,7 +722,7 @@
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in yearOptions"
|
|
|
|
|
:key="item.value"
|
|
|
|
|
:label="item.year + '年'"
|
|
|
|
|
:label="item.label || (item.year + '年')"
|
|
|
|
|
:value="item.value"
|
|
|
|
|
/>
|
|
|
|
|
</el-select>
|
|
|
|
|
@ -722,6 +735,21 @@
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="同级排序" prop="sort_order">
|
|
|
|
|
<el-input-number
|
|
|
|
|
v-model="form.sort_order"
|
|
|
|
|
:min="1"
|
|
|
|
|
:step="1"
|
|
|
|
|
controls-position="right"
|
|
|
|
|
placeholder="留空则自动排在同级最后"
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="上级预算包" prop="parent_id">
|
|
|
|
|
@ -731,6 +759,7 @@
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
clearable
|
|
|
|
|
@change="onParentChange"
|
|
|
|
|
:disabled="isMiddlePackageParentLocked"
|
|
|
|
|
>
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in parentPackageOptions"
|
|
|
|
|
@ -743,38 +772,39 @@
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="层级" prop="level">
|
|
|
|
|
<el-select v-model="form.level" placeholder="请选择层级" style="width: 100%" :disabled="!!form.parent_id">
|
|
|
|
|
<el-option label="大包" :value="1" />
|
|
|
|
|
<el-option label="中包" :value="2" />
|
|
|
|
|
</el-select>
|
|
|
|
|
<el-input :value="form.level === 1 ? '大包(自动汇总)' : '中包'" disabled />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="分配金额" prop="allocated_amount">
|
|
|
|
|
<el-form-item v-if="form.level === 1" label="自动汇总金额">
|
|
|
|
|
<el-input :value="formatCurrency(form.allocated_amount)" disabled>
|
|
|
|
|
<template slot="append">万元</template>
|
|
|
|
|
</el-input>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item v-else label="分配金额" prop="allocated_amount">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model.number="form.allocated_amount"
|
|
|
|
|
v-model="form.allocated_amount"
|
|
|
|
|
placeholder="请输入分配金额"
|
|
|
|
|
type="number"
|
|
|
|
|
:min="0"
|
|
|
|
|
:step="0.1"
|
|
|
|
|
@blur="formatAmount4('allocated_amount')"
|
|
|
|
|
type="text"
|
|
|
|
|
inputmode="decimal"
|
|
|
|
|
>
|
|
|
|
|
<template slot="append">万元</template>
|
|
|
|
|
</el-input>
|
|
|
|
|
<div v-if="isMiddlePackageDistributed" style="margin-top: 6px; color: #e6a23c; line-height: 18px;">
|
|
|
|
|
修改金额后,请由牵头科室重新分配执行科室金额。
|
|
|
|
|
</div>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="分解金额" prop="decomposed_amount">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model.number="form.decomposed_amount"
|
|
|
|
|
v-model="form.decomposed_amount"
|
|
|
|
|
placeholder="请输入分解金额(可选)"
|
|
|
|
|
type="number"
|
|
|
|
|
:min="0"
|
|
|
|
|
:step="0.1"
|
|
|
|
|
@blur="formatAmount4('decomposed_amount', true)"
|
|
|
|
|
type="text"
|
|
|
|
|
inputmode="decimal"
|
|
|
|
|
>
|
|
|
|
|
<template slot="append">万元</template>
|
|
|
|
|
</el-input>
|
|
|
|
|
@ -1079,6 +1109,8 @@ import {
|
|
|
|
|
updateBudgetCollectionPackage,
|
|
|
|
|
deleteBudgetCollectionPackage,
|
|
|
|
|
batchDeleteBudgetCollectionPackage,
|
|
|
|
|
recalculateBudgetCollectionPackageAmount,
|
|
|
|
|
recalculateBudgetCollectionYearPackageAmounts,
|
|
|
|
|
getBudgetCollectionPackageOptions,
|
|
|
|
|
getBudgetCollectionPackageSummary,
|
|
|
|
|
getEconomicClassifications
|
|
|
|
|
@ -1119,6 +1151,7 @@ export default {
|
|
|
|
|
name: '',
|
|
|
|
|
parent_id: null,
|
|
|
|
|
level: 1,
|
|
|
|
|
sort_order: null,
|
|
|
|
|
allocated_amount: 0,
|
|
|
|
|
decomposed_amount: null,
|
|
|
|
|
department_id: null,
|
|
|
|
|
@ -1243,6 +1276,18 @@ export default {
|
|
|
|
|
return this.mergeMethodByDept
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
isMiddlePackageDistributed() {
|
|
|
|
|
return this.form.level === 2 && (
|
|
|
|
|
Number(this.form.decomposed_amount || 0) > 0 ||
|
|
|
|
|
this.form.hasChildren ||
|
|
|
|
|
(Array.isArray(this.form.children) && this.form.children.length > 0)
|
|
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
isMiddlePackageParentLocked() {
|
|
|
|
|
return this.isMiddlePackageDistributed || !!this.form.submission
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 按经济分类统计合并方法
|
|
|
|
|
economicMergeMethod() {
|
|
|
|
|
return this.mergeMethodByEconomic
|
|
|
|
|
@ -1267,17 +1312,6 @@ export default {
|
|
|
|
|
this.load()
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
formatAmount4(key, allowEmpty = false) {
|
|
|
|
|
let v = this.form[key]
|
|
|
|
|
if (v === '' || v === null || v === undefined) {
|
|
|
|
|
if (allowEmpty) return
|
|
|
|
|
this.$set(this.form, key, 0)
|
|
|
|
|
v = 0
|
|
|
|
|
}
|
|
|
|
|
const num = Number(v)
|
|
|
|
|
if (!isFinite(num)) return
|
|
|
|
|
this.$set(this.form, key, Number(num.toFixed(1)))
|
|
|
|
|
},
|
|
|
|
|
initLoad() {
|
|
|
|
|
const clientHeight = document.documentElement.clientHeight
|
|
|
|
|
const lxHeaderHeight = 140
|
|
|
|
|
@ -1301,24 +1335,28 @@ export default {
|
|
|
|
|
try {
|
|
|
|
|
// 加载预算年度选项
|
|
|
|
|
const yearResponse = await getBudgetCollectionYearOptions()
|
|
|
|
|
if (yearResponse && yearResponse.code === 0) {
|
|
|
|
|
let yearData = yearResponse.data
|
|
|
|
|
|
|
|
|
|
// 如果data是字符串,尝试解析JSON
|
|
|
|
|
if (typeof yearData === 'string') {
|
|
|
|
|
try {
|
|
|
|
|
yearData = JSON.parse(yearData)
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error('解析年度选项JSON失败:', e)
|
|
|
|
|
yearData = []
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(yearData)) {
|
|
|
|
|
this.yearOptions = yearData
|
|
|
|
|
// request 拦截器成功时会直接返回 data;同时兼容未经过拦截器的响应结构。
|
|
|
|
|
let yearData = yearResponse && yearResponse.code === 0
|
|
|
|
|
? yearResponse.data
|
|
|
|
|
: yearResponse
|
|
|
|
|
|
|
|
|
|
if (yearData && !Array.isArray(yearData) && Array.isArray(yearData.data)) {
|
|
|
|
|
yearData = yearData.data
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (typeof yearData === 'string') {
|
|
|
|
|
try {
|
|
|
|
|
yearData = JSON.parse(yearData)
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error('解析年度选项JSON失败:', e)
|
|
|
|
|
yearData = []
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(yearData)) {
|
|
|
|
|
this.yearOptions = yearData
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 加载部门选项
|
|
|
|
|
const deptResponse = await listdeptNoAuth()
|
|
|
|
|
if (deptResponse) {
|
|
|
|
|
@ -1465,6 +1503,11 @@ export default {
|
|
|
|
|
if (obj) {
|
|
|
|
|
this.form = { ...this.form, ...obj }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 初始异步加载尚未完成时,确保弹窗打开前已有年度 ID 到年份文本的映射。
|
|
|
|
|
if (!this.yearOptions.length) {
|
|
|
|
|
await this.loadOptions()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置默认年度
|
|
|
|
|
if (!this.form.year_id && this.searchFields.year_id) {
|
|
|
|
|
@ -1505,6 +1548,10 @@ export default {
|
|
|
|
|
this.submitting = true
|
|
|
|
|
try {
|
|
|
|
|
const formData = { ...this.form }
|
|
|
|
|
if (formData.level === 1) {
|
|
|
|
|
// 一级大包金额是服务端汇总字段,严禁随表单提交。
|
|
|
|
|
delete formData.allocated_amount
|
|
|
|
|
}
|
|
|
|
|
// 清空 null 值
|
|
|
|
|
Object.keys(formData).forEach(key => {
|
|
|
|
|
if (formData[key] === null || formData[key] === '') {
|
|
|
|
|
@ -1568,6 +1615,52 @@ export default {
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
recalculatePackageAmount(row) {
|
|
|
|
|
this.$Modal.confirm({
|
|
|
|
|
title: '确认重新计算',
|
|
|
|
|
content: `将按直属中包金额重新计算大包“${row.name}”,是否继续?`,
|
|
|
|
|
onOk: async () => {
|
|
|
|
|
try {
|
|
|
|
|
const response = await recalculateBudgetCollectionPackageAmount(row.id)
|
|
|
|
|
const result = response && response.data ? response.data : response
|
|
|
|
|
if (result && result.skipped) {
|
|
|
|
|
this.$Message.warning(result.reason)
|
|
|
|
|
} else if (result) {
|
|
|
|
|
this.$Message.success(result.changed ? `计算完成:${result.old_amount} → ${result.new_amount} 万元` : '金额无需更新')
|
|
|
|
|
}
|
|
|
|
|
this.load()
|
|
|
|
|
} catch (error) {
|
|
|
|
|
this.$Message.error((error.response && error.response.data && error.response.data.message) || '重新计算失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
recalculateYearAmounts() {
|
|
|
|
|
if (!this.searchFields.year_id) {
|
|
|
|
|
this.$Message.warning('请先选择预算年度')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.$Modal.confirm({
|
|
|
|
|
title: '确认重算年度大包金额',
|
|
|
|
|
content: '将重新计算当前年度全部结构正常的大包金额;存在历史层级异常的大包会被安全跳过。',
|
|
|
|
|
onOk: async () => {
|
|
|
|
|
try {
|
|
|
|
|
const response = await recalculateBudgetCollectionYearPackageAmounts(this.searchFields.year_id)
|
|
|
|
|
const result = response && response.data ? response.data : response
|
|
|
|
|
if (result) {
|
|
|
|
|
const skipped = Array.isArray(result.skipped) ? result.skipped.length : 0
|
|
|
|
|
this.$Message.success(`已处理${result.processed_count || 0}个大包,更新${result.changed_count || 0}个,跳过${skipped}个`)
|
|
|
|
|
}
|
|
|
|
|
this.load()
|
|
|
|
|
} catch (error) {
|
|
|
|
|
this.$Message.error((error.response && error.response.data && error.response.data.message) || '批量重新计算失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
batchDelete() {
|
|
|
|
|
if (this.selectedRows.length === 0) {
|
|
|
|
|
this.$Message.warning('请选择要删除的记录')
|
|
|
|
|
@ -1603,6 +1696,7 @@ export default {
|
|
|
|
|
name: '',
|
|
|
|
|
parent_id: null,
|
|
|
|
|
level: 1,
|
|
|
|
|
sort_order: null,
|
|
|
|
|
allocated_amount: 0,
|
|
|
|
|
decomposed_amount: null,
|
|
|
|
|
department_id: null,
|
|
|
|
|
@ -1611,11 +1705,11 @@ export default {
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
formatCurrency(amount) {
|
|
|
|
|
if (amount === null || amount === undefined || amount === '') return '0.0'
|
|
|
|
|
if (amount === null || amount === undefined || amount === '') return '0.00'
|
|
|
|
|
const num = Number(amount)
|
|
|
|
|
return isFinite(num)
|
|
|
|
|
? num.toLocaleString('zh-CN', { minimumFractionDigits: 1, maximumFractionDigits: 1 })
|
|
|
|
|
: '0.0'
|
|
|
|
|
? num.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
|
|
|
|
: '0.00'
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
formatDate(dateStr) {
|
|
|
|
|
@ -2386,11 +2480,11 @@ export default {
|
|
|
|
|
|
|
|
|
|
// 格式化金额显示
|
|
|
|
|
formatAmount(amount) {
|
|
|
|
|
if (amount === null || amount === undefined || amount === '') return '0'
|
|
|
|
|
if (amount === null || amount === undefined || amount === '') return '0.00'
|
|
|
|
|
const num = Number(amount)
|
|
|
|
|
return isFinite(num)
|
|
|
|
|
? num.toLocaleString('zh-CN', { maximumFractionDigits: 1 })
|
|
|
|
|
: '0.0'
|
|
|
|
|
? num.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
|
|
|
|
: '0.00'
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 计算交叉表合计
|
|
|
|
|
@ -3742,4 +3836,4 @@ export default {
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
white-space: normal;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
</style>
|
|
|
|
|
|