From 237f6b8b03f28250100fd3647b6a47d09c8c207c Mon Sep 17 00:00:00 2001 From: weizong song Date: Mon, 27 Jul 2026 11:03:52 +0800 Subject: [PATCH] up --- src/api/budget/budgetCollectionYear.js | 51 +++ src/api/budget/departmentSubmission.js | 5 +- .../components/BudgetSubmissionForm.vue | 7 +- .../components/MultiPackageSubmitForm.vue | 9 +- .../components/SummarySubmitForm.vue | 7 +- src/views/budget/collection/year.vue | 298 +++++++++++++++++- 6 files changed, 367 insertions(+), 10 deletions(-) diff --git a/src/api/budget/budgetCollectionYear.js b/src/api/budget/budgetCollectionYear.js index 68601f7..da5c225 100644 --- a/src/api/budget/budgetCollectionYear.js +++ b/src/api/budget/budgetCollectionYear.js @@ -64,3 +64,54 @@ export function getBudgetCollectionYearOptions() { method: 'get' }) } + +// 获取指定年度的经济分类 +export function getYearEconomicClassifications(yearId) { + return request({ + url: `${BUDGET_API_PREFIX}/budget-collection-year/${yearId}/economic-classifications`, + method: 'get' + }) +} + +// 新增年度经济分类 +export function createYearEconomicClassification(yearId, data) { + return request({ + url: `${BUDGET_API_PREFIX}/budget-collection-year/${yearId}/economic-classifications`, + method: 'post', + data + }) +} + +// 修改年度经济分类 +export function updateYearEconomicClassification(yearId, classificationId, data) { + return request({ + url: `${BUDGET_API_PREFIX}/budget-collection-year/${yearId}/economic-classifications/${classificationId}`, + method: 'put', + data + }) +} + +// 删除未被使用的年度经济分类 +export function deleteYearEconomicClassification(yearId, classificationId) { + return request({ + url: `${BUDGET_API_PREFIX}/budget-collection-year/${yearId}/economic-classifications/${classificationId}`, + method: 'delete' + }) +} + +// 保存年度经济分类排序 +export function reorderYearEconomicClassifications(yearId, items) { + return request({ + url: `${BUDGET_API_PREFIX}/budget-collection-year/${yearId}/economic-classifications/order`, + method: 'put', + data: { items } + }) +} + +// 从最近一个更早年度复制经济分类 +export function copyPreviousYearEconomicClassifications(yearId) { + return request({ + url: `${BUDGET_API_PREFIX}/budget-collection-year/${yearId}/economic-classifications/copy-previous`, + method: 'post' + }) +} diff --git a/src/api/budget/departmentSubmission.js b/src/api/budget/departmentSubmission.js index 5d42fd0..c6a8ead 100644 --- a/src/api/budget/departmentSubmission.js +++ b/src/api/budget/departmentSubmission.js @@ -46,10 +46,11 @@ export function updateBudgetDecomposition(id, data) { } // 获取经济分类列表 -export function getEconomicCategories() { +export function getEconomicCategories(params) { return request({ url: `${BUDGET_API_PREFIX}/economic-categories`, - method: 'get' + method: 'get', + params }) } diff --git a/src/views/budget/collection/components/BudgetSubmissionForm.vue b/src/views/budget/collection/components/BudgetSubmissionForm.vue index a4b8a3b..e094ab2 100644 --- a/src/views/budget/collection/components/BudgetSubmissionForm.vue +++ b/src/views/budget/collection/components/BudgetSubmissionForm.vue @@ -826,7 +826,12 @@ export default { async loadEconomicCategories() { try { - const response = await getEconomicCategories() + const yearId = this.packageData.year_id || (this.packageData.budget_year && this.packageData.budget_year.id) + if (!yearId) { + this.$message.error('预算包缺少预算年度,无法加载经济分类') + return + } + const response = await getEconomicCategories({ year_id: yearId }) if (response && !response.errcode) { this.economicCategories = response || [] this.initEconomicCategoriesWithData() diff --git a/src/views/budget/collection/components/MultiPackageSubmitForm.vue b/src/views/budget/collection/components/MultiPackageSubmitForm.vue index 27a9c22..d16aca3 100644 --- a/src/views/budget/collection/components/MultiPackageSubmitForm.vue +++ b/src/views/budget/collection/components/MultiPackageSubmitForm.vue @@ -1034,7 +1034,12 @@ export default { async loadEconomicCategories() { try { - const response = await getEconomicCategories() + const yearId = this.mainPackage.year_id || (this.mainPackage.budget_year && this.mainPackage.budget_year.id) + if (!yearId) { + this.$message.error('预算包缺少预算年度,无法加载经济分类') + return + } + const response = await getEconomicCategories({ year_id: yearId }) if (response && !response.errcode) { this.economicCategories = response || [] this.initEconomicCategoriesWithData() @@ -1926,4 +1931,4 @@ export default { background-color: #f8f9fa; border-radius: 4px; } - \ No newline at end of file + diff --git a/src/views/budget/collection/components/SummarySubmitForm.vue b/src/views/budget/collection/components/SummarySubmitForm.vue index 15063d8..3411918 100644 --- a/src/views/budget/collection/components/SummarySubmitForm.vue +++ b/src/views/budget/collection/components/SummarySubmitForm.vue @@ -922,7 +922,12 @@ export default { async loadEconomicCategories() { try { - const response = await getEconomicCategories() + const yearId = this.packageData.year_id || (this.packageData.budget_year && this.packageData.budget_year.id) + if (!yearId) { + this.$message.error('预算包缺少预算年度,无法加载经济分类') + return + } + const response = await getEconomicCategories({ year_id: yearId }) if (response && !response.errcode) { this.economicCategories = response || [] this.initEconomicCategoriesWithData() diff --git a/src/views/budget/collection/year.vue b/src/views/budget/collection/year.vue index 6603fb2..3bda709 100644 --- a/src/views/budget/collection/year.vue +++ b/src/views/budget/collection/year.vue @@ -111,8 +111,11 @@ - + @@ -239,11 +340,16 @@ import LxHeader from '@/components/LxHeader/index.vue' import { getBudgetCollectionYearList, - getBudgetCollectionYearDetail, createBudgetCollectionYear, updateBudgetCollectionYear, deleteBudgetCollectionYear, - batchDeleteBudgetCollectionYear + batchDeleteBudgetCollectionYear, + getYearEconomicClassifications, + createYearEconomicClassification, + updateYearEconomicClassification, + deleteYearEconomicClassification, + reorderYearEconomicClassifications, + copyPreviousYearEconomicClassifications } from '@/api/budget/budgetCollectionYear.js' export default { @@ -257,6 +363,29 @@ export default { formLabelWidth: '120px', loading: false, submitting: false, + classificationDialogVisible: false, + classificationLoading: false, + classificationEditable: false, + classificationYear: null, + classificationItems: [], + classificationOrderDirty: false, + savingClassificationOrder: false, + classificationFormVisible: false, + savingClassification: false, + classificationForm: { + id: '', + name: '', + sort_order: 1 + }, + classificationRules: { + name: [ + { required: true, message: '请输入经济分类名称', trigger: 'blur' }, + { max: 100, message: '经济分类名称不能超过100个字符', trigger: 'blur' } + ], + sort_order: [ + { required: true, message: '请输入排序序号', trigger: 'change' } + ] + }, selectedRows: [], form: { id: '', @@ -319,6 +448,11 @@ export default { computed: { dialogTitle() { return this.form.id ? '编辑预算采集年份' : '新增预算采集年份' + }, + classificationDialogTitle() { + return this.classificationYear + ? `${this.classificationYear.year}年度经济分类` + : '年度经济分类' } }, created() { @@ -482,6 +616,147 @@ export default { }) }, + async openEconomicClassifications(row) { + this.classificationYear = { ...row } + this.classificationDialogVisible = true + await this.loadEconomicClassifications() + }, + + async loadEconomicClassifications() { + if (!this.classificationYear) return + this.classificationLoading = true + try { + const response = await getYearEconomicClassifications(this.classificationYear.id) + this.classificationItems = (response.items || []).map(item => ({ ...item })) + this.classificationEditable = response.editable === true + this.classificationOrderDirty = false + } catch (error) { + console.error(error) + this.classificationItems = [] + } finally { + this.classificationLoading = false + } + }, + + openClassificationForm(row) { + if (!this.classificationEditable) return + this.classificationForm = row + ? { id: row.id, name: row.name, sort_order: row.sort_order } + : { + id: '', + name: '', + sort_order: Math.max(0, ...this.classificationItems.map(item => Number(item.sort_order) || 0)) + 1 + } + this.classificationFormVisible = true + this.$nextTick(() => this.$refs.classificationForm && this.$refs.classificationForm.clearValidate()) + }, + + submitClassification() { + this.$refs.classificationForm.validate(async valid => { + if (!valid || !this.classificationYear) return + this.savingClassification = true + try { + const data = { + name: this.classificationForm.name, + sort_order: this.classificationForm.sort_order + } + if (this.classificationForm.id) { + await updateYearEconomicClassification(this.classificationYear.id, this.classificationForm.id, data) + this.$Message.success('经济分类修改成功') + } else { + await createYearEconomicClassification(this.classificationYear.id, data) + this.$Message.success('经济分类新增成功') + } + this.classificationFormVisible = false + await this.loadEconomicClassifications() + } catch (error) { + console.error(error) + } finally { + this.savingClassification = false + } + }) + }, + + moveClassification(index, offset) { + const targetIndex = index + offset + if (targetIndex < 0 || targetIndex >= this.classificationItems.length) return + const items = [...this.classificationItems] + const moved = items.splice(index, 1)[0] + items.splice(targetIndex, 0, moved) + this.classificationItems = items.map((item, itemIndex) => ({ + ...item, + sort_order: itemIndex + 1 + })) + this.classificationOrderDirty = true + }, + + async saveClassificationOrder() { + if (!this.classificationYear || !this.classificationOrderDirty) return + this.savingClassificationOrder = true + try { + const items = this.classificationItems.map(item => ({ id: item.id, sort_order: item.sort_order })) + await reorderYearEconomicClassifications(this.classificationYear.id, items) + this.$Message.success('排序保存成功') + await this.loadEconomicClassifications() + } catch (error) { + console.error(error) + } finally { + this.savingClassificationOrder = false + } + }, + + deleteClassification(row) { + if (!this.classificationYear) return + this.$confirm( + `确认删除经济分类“${row.name}”吗?已被预算填报使用的分类不能删除。`, + '确认删除', + { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning', + closeOnClickModal: false + } + ).then(async() => { + try { + await deleteYearEconomicClassification(this.classificationYear.id, row.id) + this.$Message.success('删除成功') + await this.loadEconomicClassifications() + } catch (error) { + console.error(error) + } + }).catch(action => { + if (action !== 'cancel' && action !== 'close') { + console.error(action) + } + }) + }, + + copyPreviousClassifications() { + if (!this.classificationYear) return + this.$confirm( + `将最近一个更早年度的全部经济分类复制到${this.classificationYear.year}年度。该操作仅允许在本年度分类为空时执行,是否继续?`, + '复制上一年度经济分类', + { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning', + closeOnClickModal: false + } + ).then(async() => { + try { + const response = await copyPreviousYearEconomicClassifications(this.classificationYear.id) + this.$Message.success(`已从${response.source_year}年度复制${response.copied_count}项经济分类`) + await this.loadEconomicClassifications() + } catch (error) { + console.error(error) + } + }).catch(action => { + if (action !== 'cancel' && action !== 'close') { + console.error(action) + } + }) + }, + getDefaultForm() { return { id: '', @@ -538,6 +813,21 @@ export default { padding: 12px 16px 16px 16px; /* 紧凑布局 */ } +.classification-toolbar { + display: flex; + align-items: center; + margin-bottom: 12px; +} + +.classification-count { + margin-left: auto; + color: #909399; +} + +.danger-text-button { + color: #f56c6c; +} + .v-table { border: 1px solid #e6e6e6; } @@ -572,4 +862,4 @@ export default { .el-tag { margin-right: 5px; } - \ No newline at end of file +