@@ -1,223 +1,250 @@
< template >
< div class = "app-container subsidy-page" >
< div class = "list-title" > 课时补助核算 < / div >
< div class = "top-tip" > { { tipText } } < / div >
<!-- === === === === === === == 1. 新增核算区域 === === === === === === == -- >
< el-card shadow = "never" class = "search-card ">
< div class = "form-title" > 新增 < / div >
< el-form ref = "formRef" :model = "form" :rules = "rules" label -width = " 120px " class = "search-form" >
< el-row :gutter = "0" >
<!-- 左栏 -- >
< el-col :span = "12" >
< el-form-item label = "学期名称" prop = "semesterName" >
< el-input v-model = "form.semesterName " p laceholder="请输入学期名称" clearable / >
< / el-form-item >
< el-form-item label = "开始日期" prop = "startDate ">
< el-input v-model = "form.startDate" placeholder="如:2016-03-01" clearable / >
< / el-form-item >
< el-form-item label = "课时补助标准" >
< el-select v-model = "form.subsidyStandard" placeholder="请选择" class="w-full" >
< el -option v-for = "item in subsidyStandardOptions" :key="item" :label="item" :value="item" / >
< / el-select >
<!-- === === === === === === == Tab 切换 === === === === === === == -- >
< el-tabs v-model = "activeTab" @tab-click="handleTabClick " >
< el -tab -pane label = "课时统计" name = "hour" / >
< el-tab-pane label = "课时费统计" name = "fee" / >
< / el-tabs >
<!-- === === === === === === == 1. 查询条件 === === === === === === == -- >
<!-- 课时统计 -- >
< el-card v-if = "activeTab === 'hour'" shadow="never " c lass="search-card" >
< el -form :model = "hourForm" label -width = " 100px " class = "search-form" @submit.native.prevent >
< el -row :gutter = "24 ">
< el-col :xs = "24" :sm = "12" :md = "6" >
< el-form-item label = "学期年度" >
< el-input v-model = "hourForm.nd" placeholder="如 2026" clearable / >
< / el-form-item >
< / el-col >
<!-- 右栏 -- >
< el-col :span = "12" >
< el-form-item label = "任务类别" >
< el-radio-group v-model = "form.taskCategory" >
< el -radio v-for = "item in taskCategoryOptions" :key="item.value" :label="item.value" > {{ item.label }} < / el -radio >
< / el-radio-group >
< el-col :xs = "24" :sm = "12" :md = "6" >
< el-form-item label = "学期序号" >
< el-input v-model = "hourForm.xq" placeholder="如 1" clearable / >
< / el-form-item >
< el-form-item label = "结束日期" prop = "endDate" >
< el-input v-model = "form.endDate" placeholder="如:2016-08-31" clearable / >
< / el-form-item >
< el-form-item label = "课时核算标准" >
< el-select v-model = "form.accountStandard" placeholder="请选择" class="w-full" >
< el -option v-for = "item in accountStandardOptions" :key="item" :label="item" :value="item" / >
< / el-select >
< / el-col >
< el-col :xs = "24" :sm = "12" :md = "6" >
< el-form-item label = "教员姓名" >
< el-input v-model = "hourForm.jyxm" placeholder="请输入教员姓名" clearable @keyup.enter.native="handleQuery" / >
< / el-form-item >
< / el-col >
< el-col :xs = "24" :sm = "12" :md = "6" class = "search-actions-col" >
< div class = "search-actions" >
< el-button type = "primary" @click ="handleQuery" > 查询 < / el -button >
< el-button type = "primary" plain @click ="handleExport" > 导出 Excel < / el -button >
< / div >
< / el-col >
< / el-row >
< / el-form >
< / el-card >
<!-- 课时费统计 -- >
< el-card v-else shadow = "never" class = "search-card" >
< el-form :model = "feeForm" label -width = " 100px " class = "search-form" @submit.native.prevent >
< el -row :gutter = "24" >
< el-col :xs = "24" :sm = "12" :md = "6" >
< el-form-item label = "学期年度" >
< el-input v-model = "feeForm.nd" placeholder="如 2026" clearable / >
< / el-form-item >
< / el-col >
< el-col :xs = "24" :sm = "12" :md = "6" >
< el-form-item label = "学期序号" >
< el-input v-model = "feeForm.xq" placeholder="如 1" clearable / >
< / el-form-item >
< / el-col >
< el-col :xs = "24" :sm = "12" :md = "6" >
< el-form-item label = "教员姓名" >
< el-input v-model = "feeForm.jyxm" placeholder="请输入教员姓名" clearable / >
< / el-form-item >
< / el-col >
< el-col :xs = "24" :sm = "12" :md = "6" >
< el-form-item label = "标准编号" >
< el-input v-model = "feeForm.ksfbzbh" placeholder="课时费标准编号" clearable / >
< / el-form-item >
< / el-col >
< el-col :span = "24" class = "search-actions-col" >
< div class = "search-actions" >
< el-button type = "primary" :loading = "addLoading" @click ="handleAdd " > 添加 < / el -button >
< el-button type = "primary" @click ="handleQuery " > 查询 < / el -button >
< el-button type = "primary" plain @click ="handleExport" > 导出 Excel < / el -button >
< / div >
< / el-col >
< / el-row >
< / el-form >
< / el-card >
<!-- === === === === === === == 2. 数据表格 === === === === === === == -- >
< el-card shadow = "never" class = "table-card" >
< el-table v-loading = "queryLoading" :data="tableData" border stripe style="width: 100%" >
< el -table -column label = "详细" width = "80" fixed align = "center ">
< template slot -scope = " { row } " >
< el-button type = "text" @click ="handleDetail(row)" > 详细 < / el -button >
< / template >
< div class = "table-title" > { { activeTab === 'hour' ? '课时统计列表' : '课时费统计列表' } } < / div >
< el-table v-loading = "currentState.loading" :data="currentState.list" border stripe style="width: 100% ">
< el -table -column type = "index" label = "序号" width = "55" align = "center" / >
< el-table-column prop = "jysdh" label = "教研室代号" width = "100" align = "center" show -overflow -tooltip / >
< el-table-column prop = "jysmc" label = "教研室名称" width = "120" show -overflow -tooltip / >
< el-table-column prop = "jybh" label = "教员编号" width = "110" align = "center" show -overflow -tooltip / >
< el-table-column prop = "jyxm" label = "教员姓名" width = "100" align = "center" show -overflow -tooltip / >
< el-table-column prop = "zc" label = "职称" width = "90" align = "center" show -overflow -tooltip / >
< el-table-column prop = "nf" label = "年份" width = "70" align = "center" / >
< el-table-column prop = "sbn" label = "上半年" width = "90" align = "right" >
< template slot -scope = " { row } " > { { fmtValue ( row . sbn ) } } < / template >
< / el-table-column >
< el-table-column prop = "semesterName " label = "学期名称 " width = "12 0" / >
< el-table-column prop = "taskCategory" label = "任务类别" width = "180" / >
< el-table-column prop = "startDate" label = "核算开始日期" width = "120" / >
< el-table-column prop = "endDate " label = "核算结束日期 " width = "12 0" / >
< el-table-column prop = "totalHours" label = "总课时量" width = "100" align = "right" / >
< el-table-column prop = "qualityHours" label = "优质课时量" width = "100" align = "right" / >
< el-table-column prop = "qualityRatio " label = "优质 课时量比例 " width = "12 0" align = "right" / >
< el-table-column prop = "totalSubsidy" label = "总补助金额" width = "120" align = "right" / >
< el-table-column prop = "accountStandard" label = "课时核算标准" show -overflow -tooltip / >
< el-table-column prop = "subsidyStandard " label = "课时补助标准 " width = "18 0" show -overflow -tooltip / >
< el-table-column prop = "status" label = "状态" width = "100" align = "center" >
< template slot -scope = " { row } " >
< span : class = "row.status === '已核算' ? 'status-done' : 'status-doing'" >
{ { row . status } }
< / span >
< / template >
< el-table-column prop = "xbn " label = "下半年 " width = "9 0" align = "right" >
< template slot -scope = " { row } " > { { fmtValue ( row . xbn ) } } < / template >
< / el-table-column >
< el-table-column prop = "zj " label = "总计 " width = "9 0" align = "right" >
< template slot -scope = " { row } " > { { fmtValue ( row . zj ) } } < / template >
< / el-table-column >
< el-table-column prop = "bzksl " label = "标准 课时量" width = "10 0" align = "right" >
< template slot -scope = " { row } " > { { fmtValue ( row . bzksl ) } } < / template >
< / el-table-column >
< el-table-column prop = "cks " label = "超 课时" width = "9 0" align = "right" >
< template slot -scope = " { row } " > { { fmtValue ( row . cks ) } } < / template >
< / el-table-column >
< el-table-column prop = "jsgs" label = "计算过程" min -width = " 140 " show -overflow -tooltip / >
< el-table-column prop = "jg" label = "结果" width = "90" align = "right" >
< template slot -scope = " { row } " > { { fmtValue ( row . jg ) } } < / template >
< / el-table-column >
< el-table-column prop = "ksfbzmc" label = "课时费标准" width = "110" align = "center" show -overflow -tooltip / >
< el-table-column prop = "ksfbz" label = "课时费单价" width = "100" align = "right" >
< template slot -scope = " { row } " > { { fmtValue ( row . ksfbz ) } } < / template >
< / el-table-column >
< el-table-column prop = "clksfbz" label = "超量课时费单价" width = "110" align = "right" >
< template slot -scope = " { row } " > { { fmtValue ( row . clksfbz ) } } < / template >
< / el-table-column >
< / el-table >
< div class = "table-footer" >
< span > 总记录数 : { { tableData . length } } 条 < / span >
< span > 总课时量 : { { totalHours } } < / span >
< span > 优质课时量 : { { totalQualityHours } } < / span >
< span > 总补助金额 : { { totalSubsidy } } 元 < / span >
< / div >
< el-pagination
:current-page = "currentState.pageNum"
:page-size = "currentState.pageSize"
:total = "currentState.total"
: page -sizes = " [ 10 , 20 , 50 , 100 ] "
layout = "total, sizes, prev, pager, next, jumper"
class = "pagination"
@ current -change = " handlePageChange "
@ size -change = " handleSizeChange "
/ >
< / el-card >
<!-- === === === === === === == 3. 详情对话框 === === === === === === == -- >
< el-dialog
:visible = "detailVisible"
title = "课时补助核算详情"
width = "560px"
:close-on-click-modal = "false"
@ update : visible = "val => detailVisible = val"
>
< el-descriptions v-if = "detailRow" :column="1" border >
< el-descriptions-item label = "学期名称" > { { detailRow . semesterName } } < / el-descriptions-item >
< el-descriptions-item label = "任务类别" > { { detailRow . taskCategory } } < / el-descriptions-item >
< el-descriptions-item label = "核算开始日期" > { { detailRow . startDate } } < / el-descriptions-item >
< el-descriptions-item label = "核算结束日期" > { { detailRow . endDate } } < / el-descriptions-item >
< el-descriptions-item label = "总课时量" > { { detailRow . totalHours } } < / el-descriptions-item >
< el-descriptions-item label = "优质课时量" > { { detailRow . qualityHours } } < / el-descriptions-item >
< el-descriptions-item label = "优质课时量比例" > { { detailRow . qualityRatio } } < / el-descriptions-item >
< el-descriptions-item label = "总补助金额" > { { detailRow . totalSubsidy } } 元 < / el-descriptions-item >
< el-descriptions-item label = "课时核算标准" > { { detailRow . accountStandard } } < / el-descriptions-item >
< el-descriptions-item label = "课时补助标准" > { { detailRow . subsidyStandard } } < / el-descriptions-item >
< el-descriptions-item label = "状态" > { { detailRow . status } } < / el-descriptions-item >
< / el-descriptions >
< div slot = "footer" >
< el-button @click ="detailVisible = false" > 关闭 < / el -button >
< / div >
< / el-dialog >
< / div >
< / template >
< script >
// 模拟核算列表数据(后端接口未提供,接口就绪后可删除并改为接口加载)
const mockSummaryData = [
{ bh : 'H001' , mc : '2022年秋季学期课时补助核算' , rwlb : '全军院校训练规划内任务' , hsksrq : '2022-09-01T00:00:00' , hsjsrq : '2023-01-15T00:00:00' , zksl : 1200 , yzksl : 800 , yzkslbl : 0.6667 , zbzje : 24000 , zt : '已核算' } ,
{ bh : 'H002' , mc : '2022年春季学期课时补助核算' , rwlb : '其他任务(含研究生导师指导)' , hsksrq : '2022-03-01T00:00:00' , hsjsrq : '2022-08-31T00:00:00' , zksl : 900 , yzksl : 540 , yzkslbl : 0.6 , zbzje : 18000 , zt : '核算中' } ,
{ bh : 'H003' , mc : '2021年秋季学期课时补助核算' , rwlb : '全军院校训练规划内任务' , hsksrq : '2021-09-01T00:00:00' , hsjsrq : '2022-01-15T00:00:00' , zksl : 1100 , yzksl : 770 , yzkslbl : 0.7 , zbzje : 22000 , zt : '已核算' }
]
import { saveAs } from 'file-saver'
import {
listHourStatistics ,
exportHourStatistics ,
listFeeStatistics ,
exportFeeStatistics
} from '@/api/classHour/hourStat'
export default {
name : 'SubsidyIndex' ,
data ( ) {
return {
// ==================== 顶部提示条 ====================
tipText : '提示:"课时核算"和"补助核算"要花费稍微长一点时间,操作后请耐心等待系统"操作成功"的提示! ' ,
// ==================== Tab ====================
activeTab : 'hour ' ,
// ==================== 下拉选项 ====================
subsidyStandardOptions : [ '2022年秋季学期' , '2022年春季学期' , '2021年秋季学期' , '2021年春季学期' ] ,
accountStandardOptions : [ '2022年秋季学期课时补助核算' , '2022年春季学期课时补助核算' , '2021年秋季学期课时补助核算' , '2021年春季学期课时补助核算' ] ,
taskCategoryOptions : [
{ label : '全军院校训练规划内任务' , value : '全军院校训练规划内任务' } ,
{ label : '其他任务(含研究生导师指导)' , value : '其他任务(含研究生导师指导)' }
] ,
// ==================== 新增表单 ====================
form : {
semesterName : '' ,
taskCategory : '全军院校训练规划内任务' ,
startDate : '' ,
endDate : '' ,
subsidyStandard : '2022年秋季学期' ,
accountStandard : '2022年秋季学期课时补助核算'
// ==================== 课时统计查询条件 ====================
hourForm : {
nd : '' ,
xq : '' ,
jyxm : ''
} ,
rules : {
semesterName : [ { required : true , message : '请输入学期名称' , trigger : 'blur' } ] ,
startDate : [ { required : true , message : '请输入开始日期' , trigger : 'blur' } ] ,
endDate : [ { required : true , message : '请输入结束日期' , trigger : 'blur' } ]
// ==================== 课时费统计查询条件 ====================
feeForm : {
nd : '' ,
xq : '' ,
jyxm : '' ,
ksfbzbh : ''
} ,
addLoading : false ,
// ==================== 表格数据 ====================
tableData : [ ] ,
queryLoading : false ,
// ==================== 详情对话框 ====================
detailVisible : false ,
detailRow : null
// ==================== 各 Tab 列表状态 ====================
hourState : this . createEmptyState ( ) ,
feeState : this . createEmptyState ( )
}
} ,
computed : {
totalHours ( ) {
return this . tableData . reduce ( ( sum , r ) => sum + Number ( r . totalHours || 0 ) , 0 )
currentForm ( ) {
return this . activeTab === 'hour' ? this . hourForm : this . feeForm
} ,
totalQualityHours ( ) {
return this . tableData . reduce ( ( sum , r ) => sum + Number ( r . qualityHours || 0 ) , 0 )
} ,
totalSubsidy ( ) {
return this . tableData . reduce ( ( sum , r ) => sum + Number ( r . totalSubsidy || 0 ) , 0 )
currentState ( ) {
return this . activeTab === 'hour' ? this . hourState : this . feeState
}
} ,
mounted ( ) {
this . handleQuery ( )
this . fetchList ( )
} ,
methods : {
// ==================== 查询核算列表 ====================
// TODO: 后端接口未提供,暂用模拟数据;接口就绪后替换为 /log/summary/list
handleQuery ( ) {
this . queryLoading = true
setTimeout ( ( ) => {
this . tableData = mockSummaryData . map ( ( item , idx ) => ( {
id : idx + 1 ,
_bh : item . bh || '' ,
semesterName : item . mc || '-' ,
taskCategory : item . rwlb || '-' ,
startDate : ( item . hsksrq || '' ) . substring ( 0 , 10 ) || '-' ,
endDate : ( item . hsjsrq || '' ) . substring ( 0 , 10 ) || '-' ,
totalHours : item . zksl || 0 ,
qualityHours : item . yzksl || 0 ,
qualityRatio : item . zksl > 0 ? ( ( item . yzkslbl || 0 ) * 100 ) . toFixed ( 2 ) + '%' : '0.00%' ,
totalSubsidy : item . zbzje || 0 ,
accountStandard : item . mc || '-' ,
subsidyStandard : '-' ,
status : item . zt || '-'
} ) )
this . $message . success ( ` 查询完成,共 ${ this . tableData . length } 条记录(前端模拟) ` )
this . queryLoading = false
} , 200 )
createEmptyState ( ) {
return { list : [ ] , loading : false , pageNum : 1 , pageSize : 20 , total : 0 }
} ,
// ==================== 添加 ====================
// TODO: 后端接口未提供,提交为前端模拟;接口就绪后替换为 /log/subsidy-project/add
handleAdd ( ) {
this . $refs . formRef . validate ( ( valid ) => {
if ( ! valid ) {
this . $message . warning ( '请完善必填项后再提交' )
return
}
this . addLoading = true
setTimeout ( ( ) => {
this . $message . success ( '核算提交成功(前端模拟)' )
this . handleQuery ( )
this . addLoading = false
} , 300 )
/** 构建查询参数,仅传非空字段(与后端 Query 字段一致) */
buildParams ( form ) {
const params = { }
if ( form . nd && form . nd . trim ( ) ) params . nd = form . nd . trim ( )
if ( form . xq && form . xq . trim ( ) ) params . xq = form . xq . trim ( )
if ( form . jyxm && form . jyxm . trim ( ) ) params . jyxm = form . jyxm . trim ( )
if ( form . ksfbzbh && form . ksfbzbh . trim ( ) ) params . ksfbzbh = form . ksfbzbh . trim ( )
return params
} ,
// ==================== 查询 ====================
fetchList ( ) {
const state = this . currentState
const form = this . currentForm
const params = Object . assign (
{ pageNum : state . pageNum , pageSize : state . pageSize } ,
this . buildParams ( form )
)
state . loading = true
const req = this . activeTab === 'hour' ? listHourStatistics ( params ) : listFeeStatistics ( params )
req . then ( res => {
const data = ( res && res . data ) || { }
state . list = data . records || [ ]
state . total = data . total || 0
} ) . catch ( ( ) => {
state . list = [ ]
state . total = 0
} ) . finally ( ( ) => {
state . loading = false
} )
} ,
// ==================== 详情对话框 ====================
handleDetail ( row ) {
this . detailRow = row
this . detailVisible = true
handleTabClick ( ) {
this . currentState . pageNum = 1
this . fetchList ( )
} ,
handleQuery ( ) {
this . currentState . pageNum = 1
this . fetchList ( )
} ,
handlePageChange ( page ) {
this . currentState . pageNum = page
this . fetchList ( )
} ,
handleSizeChange ( size ) {
this . currentState . pageSize = size
this . currentState . pageNum = 1
this . fetchList ( )
} ,
// ==================== 导出 ====================
handleExport ( ) {
const clean = this . buildParams ( this . currentForm )
const isHour = this . activeTab === 'hour'
const req = isHour ? exportHourStatistics ( clean ) : exportFeeStatistics ( clean )
const fileName = isHour ? '课时统计.xlsx' : '课时费统计.xlsx'
req . then ( blob => {
saveAs ( blob , fileName )
this . $message . success ( '导出成功' )
} ) . catch ( ( ) => { } )
} ,
/** 数值空值显示为 '-'(保留 0) */
fmtValue ( val ) {
return val === null || val === undefined ? '-' : val
}
}
}
@@ -236,63 +263,37 @@ export default {
margin - bottom : 12 px ;
}
. top - tip {
color : # f56c6c ;
font - size : 13 px ;
margin - bottom : 16 px ;
line - height : 1.6 ;
}
// ==================== 1. 查询条件区域 ====================
. search - card {
margin - bottom : 16 px ;
. form - title {
font - size : 14 px ;
font - weight : 600 ;
color : # 303133 ;
margin - bottom : 12 px ;
padding - bottom : 8 px ;
border - bottom : 1 px solid # ebeef5 ;
}
. search - form {
. w - full {
width : 100 % ;
. search - actions - col {
display : flex ;
align - items : center ;
}
. search - actions {
display : flex ;
justify - content : flex - end ;
margin - top : 8 px ;
padding - top : 12 px ;
border - top : 1 px solid # ebeef5 ;
gap : 12 px ;
}
}
}
// ==================== 2. 数据表格 ====================
. table - card {
. el - table {
width : 100 % ;
. table - title {
font - size : 14 px ;
font - weight : 600 ;
color : # 303133 ;
margin - bottom : 12 px ;
}
. table - footer {
. pagination {
display : flex ;
flex - wrap : wrap ;
gap : 24 px ;
justify - content : flex - end ;
margin - top : 12 px ;
padding - top : 12 px ;
border - top : 1 px solid # ebeef5 ;
font - size : 12 px ;
color : # 606266 ;
}
}
. status - done {
color : # 67 c23a ;
}
. status - doing {
color : # e6a23c ;
}
}
< / style >