From bac4110db32d0fb41656cfb661ca8adc562409e3 Mon Sep 17 00:00:00 2001 From: weizong song Date: Thu, 30 Jul 2026 11:06:05 +0800 Subject: [PATCH] feat: refine department review interactions --- src/views/budget/departmentReview/index.vue | 324 +++++++++++++++++--- 1 file changed, 285 insertions(+), 39 deletions(-) diff --git a/src/views/budget/departmentReview/index.vue b/src/views/budget/departmentReview/index.vue index e660e63..ee82200 100644 --- a/src/views/budget/departmentReview/index.vue +++ b/src/views/budget/departmentReview/index.vue @@ -106,26 +106,19 @@ - + @@ -158,6 +151,109 @@ @cancel="detailDialogVisible = false" /> + + +
+
+ +
+
+
审核操作
+ + {{ getParentPackageName(currentReviewRow) }} + {{ getPackageName(currentReviewRow) }} + {{ getDepartmentName(currentReviewRow) }} + {{ getStatusText(currentReviewRow.status) }} + {{ formatDate(currentReviewRow.submitted_at) }} + + + + + + 通过 + 退回 + + + + + + + +
最近审核记录
+
+
+
+ {{ getHistoryActionText(history) }} + {{ formatDate(history.operated_at) }} +
+
+ {{ history.operator ? history.operator.name : '-' }} · {{ getHistoryStatusFlow(history) }} +
+
{{ history.notes }}
+
+
+ + + +
+
+
+ + +
+ + {{ getParentPackageName(currentHistoryRow) }} + {{ getPackageName(currentHistoryRow) }} + {{ getDepartmentName(currentHistoryRow) }} + {{ getStatusText(currentHistoryRow.status) }} + + + +
+
{{ getHistoryActionText(history) }}
+
{{ history.operator ? history.operator.name : '-' }} · {{ getHistoryStatusFlow(history) }}
+
{{ history.notes }}
+
+
+
+ +
+
@@ -188,7 +284,16 @@ export default { pageSize: 15, yearOptions: [], detailDialogVisible: false, - currentPackage: null + reviewDialogVisible: false, + historyDialogVisible: false, + currentPackage: null, + currentReviewRow: null, + currentHistoryRow: null, + reviewSubmitting: false, + reviewForm: { + action: 'approve', + approval_notes: '' + } } }, created() { @@ -262,35 +367,47 @@ export default { this.detailDialogVisible = true }, - async approveSubmission(row) { - try { - await reviewDepartmentSubmission(row.id, { action: 'approve' }) - this.$message.success('审核通过') - this.load() - } catch (error) { - console.error('执行科室分解审核失败:', error) + openReviewDialog(row) { + if (!row.package) { + this.$message.warning('预算包数据不存在') + return } + this.currentReviewRow = row + this.currentPackage = { ...row.package } + this.reviewForm = { + action: 'approve', + approval_notes: '' + } + this.reviewDialogVisible = true }, - async returnSubmission(row) { + openHistoryDialog(row) { + this.currentHistoryRow = row + this.historyDialogVisible = true + }, + + async submitReview() { + if (!this.currentReviewRow) { + return + } + if (this.reviewForm.action === 'return' && !this.reviewForm.approval_notes.trim()) { + this.$message.warning('请输入退回修改意见') + return + } + + this.reviewSubmitting = true try { - const result = await this.$prompt('请输入退回修改意见', '退回执行科室分解', { - confirmButtonText: '确认退回', - cancelButtonText: '取消', - inputValidator: value => Boolean(value && value.trim()), - inputErrorMessage: '退回意见不能为空' + await reviewDepartmentSubmission(this.currentReviewRow.id, { + action: this.reviewForm.action, + approval_notes: this.reviewForm.approval_notes.trim() }) - await reviewDepartmentSubmission(row.id, { - action: 'return', - approval_notes: result.value.trim() - }) - this.$message.success('已退回执行科室修改') - this.load() + this.$message.success(this.reviewForm.action === 'approve' ? '审核通过' : '已退回执行科室修改') + this.reviewDialogVisible = false + await this.load() } catch (error) { - if (error === 'cancel' || error === 'close') { - return - } - console.error('退回执行科室分解失败:', error) + console.error('执行科室分解审核失败:', error) + } finally { + this.reviewSubmitting = false } }, @@ -355,6 +472,28 @@ export default { approved: '审核通过' } return textMap[status] || '未知' + }, + + reviewHistories(row) { + return (row.review_histories || []).slice().sort((a, b) => { + return new Date(b.operated_at || 0).getTime() - new Date(a.operated_at || 0).getTime() + }) + }, + + getHistoryActionText(history) { + const actionMap = { + submit: '提交审核', + resubmit: '重新提交', + approve: '审核通过', + return: '退回修改' + } + return actionMap[history.action] || history.action || '未知操作' + }, + + getHistoryStatusFlow(history) { + const fromText = this.getStatusText(history.from_status) + const toText = this.getStatusText(history.to_status) + return `${fromText} -> ${toText}` } } } @@ -373,16 +512,113 @@ export default { } .filters, -.actions, -.action-group { +.actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } -.process-note { +.action-group { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + flex-wrap: nowrap; + white-space: nowrap; +} + +.review-layout { + display: flex; + gap: 16px; + align-items: flex-start; +} + +.review-detail-panel { + min-width: 0; + flex: 1 1 auto; +} + +.review-action-panel { + width: 360px; + padding: 16px; + border: 1px solid #ebeef5; + border-radius: 8px; + background: #fafbfd; +} + +.panel-title { margin-bottom: 12px; + color: #303133; + font-size: 16px; + font-weight: 600; +} + +.panel-title-spaced { + margin-top: 20px; +} + +.review-summary, +.history-summary { + margin-bottom: 16px; +} + +.review-form { + margin-top: 16px; +} + +.inline-history-list { + display: flex; + flex-direction: column; + gap: 10px; +} + +.inline-history-item, +.timeline-card { + padding: 12px; + border: 1px solid #ebeef5; + border-radius: 6px; + background: #fff; +} + +.inline-history-head { + display: flex; + justify-content: space-between; + gap: 12px; + margin-bottom: 6px; + color: #303133; + font-weight: 600; +} + +.inline-history-meta, +.timeline-meta { + color: #909399; + font-size: 12px; +} + +.inline-history-notes, +.timeline-notes { + margin-top: 8px; + color: #606266; + line-height: 1.6; + word-break: break-all; +} + +.timeline-title { + margin-bottom: 6px; + color: #303133; + font-weight: 600; +} + +.history-timeline { + margin-top: 20px; +} + +.review-action-footer { + display: flex; + justify-content: flex-end; + gap: 12px; + margin-top: 20px; } .package-name { @@ -394,4 +630,14 @@ export default { color: #409EFF; font-weight: 600; } + +@media (max-width: 1400px) { + .review-layout { + flex-direction: column; + } + + .review-action-panel { + width: 100%; + } +}