This commit is contained in:
2026-08-25 14:48:51 +08:00
parent 656ee817e6
commit ebf4928e3f
2 changed files with 340 additions and 444 deletions
@@ -0,0 +1,89 @@
import request from '@/utils/request'
// 课表查询管理(KCBController /kcb,前端 baseURL 为 /api,此处不重复 /api 前缀)
// 接口依据:课表页面接口规格
// 查询实体 TimetableQuery:nd 年度(可选,不传自动取当前学期)、xydbh 学员队编号/班次(可选,按班次筛选)
/**
* 今日课表
* GET /kcb/today/list
* @param params TimetableQuerynd、xydbh(均可选)
* 返回:今日课表记录(实体字段 bh/sksj/kc/zrdw/bc/jy/cd/jxnrxff/bz
*/
export function listToday(data) {
return request({
url: '/kcb/today/list',
method: 'get',
params: data
})
}
/**
* 本周课表
* GET /kcb/week/list
* @param params TimetableQuerynd、xydbh(均可选)
* 返回:本周课表记录
*/
export function listWeek(data) {
return request({
url: '/kcb/week/list',
method: 'get',
params: data
})
}
/**
* 班次课表(分页)
* GET /kcb/class/list
* @param params pageNum、pageSizecond=TimetableQuerynd、xydbh
* 返回:PageResult<班次课程记录>records/total
*/
export function listClass(params) {
return request({
url: '/kcb/class/list',
method: 'get',
params
})
}
/**
* 下载学期教学实施计划 Excel
* GET /kcb/class/export-plan
* @param data TimetableQuerynd、xydbh
*/
export function exportClassPlan(data) {
return request({
url: '/kcb/class/export-plan',
method: 'get',
params: data,
responseType: 'blob'
})
}
/**
* 下载学期成绩表 Excel
* GET /kcb/class/export-grades
* @param data TimetableQuerynd、xydbh
*/
export function exportClassGrades(data) {
return request({
url: '/kcb/class/export-grades',
method: 'get',
params: data,
responseType: 'blob'
})
}
/**
* 班次课程列表另存 Excel
* GET /kcb/class/export-courses
* @param data TimetableQuerynd、xydbh
*/
export function exportClassCourses(data) {
return request({
url: '/kcb/class/export-courses',
method: 'get',
params: data,
responseType: 'blob'
})
}
@@ -1,228 +1,126 @@
<template> <template>
<div class="app-container timetable-page"> <div class="app-container timetable-page">
<el-tabs v-model="activeTab" class="timetable-tabs"> <el-tabs v-model="activeTab" class="timetable-tabs">
<!-- 今日 --> <!-- ==================== 今日教学实施计划 ==================== -->
<el-tab-pane label="今日" name="today"> <el-tab-pane label="今日教学实施计划" name="today">
<div class="tab-body"> <div class="tab-body">
<!-- 日期导航 --> <div class="date-header">
<div class="nav-header">
<el-link type="primary" :underline="false" class="nav-link" @click="handlePrevDay">前一天</el-link> <el-link type="primary" :underline="false" class="nav-link" @click="handlePrevDay">前一天</el-link>
<div class="nav-title">{{ todayTitle }}</div> <div class="date-title">{{ dateTitle }}</div>
<el-link type="primary" :underline="false" class="nav-link" @click="handleNextDay">后一天</el-link> <el-link type="primary" :underline="false" class="nav-link" @click="handleNextDay">后一天</el-link>
</div> </div>
<!-- 今日表格 -->
<div class="table-card"> <div class="table-card">
<el-table :data="todayList" v-loading="todayLoading" stripe border> <el-table :data="todayData" v-loading="loading" stripe border>
<el-table-column type="index" label="序号" width="55" align="center" /> <el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column label="上课时间" width="200" align="center" show-overflow-tooltip> <el-table-column label="上课时间" width="130" align="center">
<template slot-scope="scope">{{ fmtLessonTime(scope.row) }}</template> <template #default="{ row }">{{ formatJc(row.jc) }}</template>
</el-table-column> </el-table-column>
<el-table-column prop="kcmc" label="课程" min-width="150" show-overflow-tooltip header-align="center" /> <el-table-column prop="kcmc" label="课程" min-width="140" show-overflow-tooltip header-align="center" />
<el-table-column prop="kcxh" label="课次序号" width="90" align="center" /> <el-table-column prop="zrdw" label="责任单位" width="110" align="center" />
<el-table-column label="教学内容" min-width="180" show-overflow-tooltip header-align="center"> <el-table-column prop="bc" label="班次" width="120" show-overflow-tooltip header-align="center" />
<template slot-scope="scope">{{ scope.row.jxnr || '-' }}</template> <el-table-column prop="skjy" label="教员" width="90" align="center" />
<el-table-column label="场地" width="140" show-overflow-tooltip header-align="center">
<template #default="{ row }">{{ row.jxcd || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column label="教学方法" width="130" align="center" show-overflow-tooltip> <el-table-column label="教学内容方法" min-width="160" show-overflow-tooltip header-align="center">
<template slot-scope="scope">{{ scope.row.jxff || '-' }}</template> <template #default="{ row }">{{ row.jxnrff || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column label="填写状态" width="100" align="center"> <el-table-column prop="jybz" label="备注" width="100" show-overflow-tooltip header-align="center">
<template slot-scope="scope"> <template #default="{ row }">{{ row.jybz || '-' }}</template>
<el-tag :type="txztType(scope.row.txzt)" size="mini">{{ txztText(scope.row.txzt) }}</el-tag>
</template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<el-empty v-show="!todayLoading && !todayList.length" description="当日暂无教学计划数据" /> <el-empty v-show="!loading && !todayData.length" description="暂无教学计划数据" />
</div> </div>
</div> </div>
</el-tab-pane> </el-tab-pane>
<!-- 本周 --> <!-- ==================== 本周教学实施计划 ==================== -->
<el-tab-pane label="本周" name="week"> <el-tab-pane label="本周教学实施计划" name="week">
<div class="tab-body"> <div class="tab-body">
<!-- 周次导航 --> <div class="week-header">
<div class="nav-header">
<el-link type="primary" :underline="false" class="nav-link" @click="handlePrevWeek">上一周</el-link> <el-link type="primary" :underline="false" class="nav-link" @click="handlePrevWeek">上一周</el-link>
<div class="nav-title">{{ weekTitle }}</div> <div class="week-title">{{ weekRangeText }}</div>
<el-link type="primary" :underline="false" class="nav-link" @click="handleNextWeek">下一周</el-link> <el-link type="primary" :underline="false" class="nav-link" @click="handleNextWeek">下一周</el-link>
</div> </div>
<!-- 本周表格 -->
<div class="table-card"> <div class="table-card">
<el-table :data="weekList" v-loading="weekLoading" stripe border> <el-table :data="weekData" v-loading="loading" stripe border>
<el-table-column type="index" label="序号" width="55" align="center" /> <el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column label="上课时间" width="200" align="center" show-overflow-tooltip> <el-table-column label="上课时间" width="170" align="center" show-overflow-tooltip>
<template slot-scope="scope">{{ fmtLessonTime(scope.row) }}</template> <template #default="{ row }">{{ row.sjsj || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column prop="kcmc" label="课程" min-width="150" show-overflow-tooltip header-align="center" /> <el-table-column prop="kcmc" label="课程" min-width="130" show-overflow-tooltip header-align="center" />
<el-table-column prop="kcxh" label="课次序号" width="90" align="center" /> <el-table-column prop="zrdw" label="责任单位" width="100" align="center" />
<el-table-column label="教学内容" min-width="180" show-overflow-tooltip header-align="center"> <el-table-column prop="bc" label="班次" width="130" show-overflow-tooltip header-align="center" />
<template slot-scope="scope">{{ scope.row.jxnr || '-' }}</template> <el-table-column prop="skjy" label="教员" width="90" align="center" />
<el-table-column label="场地" width="140" show-overflow-tooltip header-align="center">
<template #default="{ row }">{{ row.jxcd || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column label="教学方法" width="130" align="center" show-overflow-tooltip> <el-table-column label="教学内容方法" min-width="150" show-overflow-tooltip header-align="center">
<template slot-scope="scope">{{ scope.row.jxff || '-' }}</template> <template #default="{ row }">{{ row.jxnrff || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column label="填写状态" width="100" align="center"> <el-table-column prop="jybz" label="备注" width="100" show-overflow-tooltip header-align="center">
<template slot-scope="scope"> <template #default="{ row }">{{ row.jybz || '-' }}</template>
<el-tag :type="txztType(scope.row.txzt)" size="mini">{{ txztText(scope.row.txzt) }}</el-tag>
</template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<el-empty v-show="!weekLoading && !weekList.length" description="本周暂无教学计划数据" /> <el-empty v-show="!loading && !weekData.length" description="本周暂无教学计划数据" />
<pagination
v-show="weekTotal > 0"
:total="weekTotal"
:page.sync="weekQuery.pageNum"
:limit.sync="weekQuery.pageSize"
@pagination="getWeekList"
/>
</div> </div>
</div> </div>
</el-tab-pane> </el-tab-pane>
<!-- 三实 --> <!-- ==================== 教学班次教学实施计划 ==================== -->
<el-tab-pane label="三实" name="practice"> <el-tab-pane label="教学班次教学实施计划" name="shift">
<div class="tab-body"> <div class="tab-body">
<!-- 周次导航 --> <!-- 选择条件 -->
<div class="nav-header"> <div class="search-card">
<el-link type="primary" :underline="false" class="nav-link" @click="handlePrevWeek3">上一周</el-link> <el-form :model="searchForm" inline class="search-form">
<div class="nav-title">{{ practiceTitle }}</div>
<el-link type="primary" :underline="false" class="nav-link" @click="handleNextWeek3">下一周</el-link>
</div>
<!-- 三实表格 -->
<div class="table-card">
<el-table :data="practiceList" v-loading="practiceLoading" stripe border>
<el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column label="上课时间" width="200" align="center" show-overflow-tooltip>
<template slot-scope="scope">{{ fmtLessonTime(scope.row) }}</template>
</el-table-column>
<el-table-column prop="kcmc" label="课程" min-width="150" show-overflow-tooltip header-align="center" />
<el-table-column prop="kcxh" label="课次序号" width="90" align="center" />
<el-table-column label="教学内容" min-width="180" show-overflow-tooltip header-align="center">
<template slot-scope="scope">{{ scope.row.jxnr || '-' }}</template>
</el-table-column>
<el-table-column label="教学方法" width="130" align="center" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.jxff || '-' }}</template>
</el-table-column>
<el-table-column label="填写状态" width="100" align="center">
<template slot-scope="scope">
<el-tag :type="txztType(scope.row.txzt)" size="mini">{{ txztText(scope.row.txzt) }}</el-tag>
</template>
</el-table-column>
</el-table>
<el-empty v-show="!practiceLoading && !practiceList.length" description="本周暂无三实教学计划数据" />
<pagination
v-show="practiceTotal > 0"
:total="practiceTotal"
:page.sync="practiceQuery.pageNum"
:limit.sync="practiceQuery.pageSize"
@pagination="getPracticeList"
/>
</div>
</div>
</el-tab-pane>
<!-- 班次 -->
<el-tab-pane label="班次" name="shift">
<div class="tab-body">
<!-- 查询条件 -->
<el-form :inline="true" class="shift-search">
<el-form-item label="队别班次"> <el-form-item label="队别班次">
<el-select <el-select v-model="searchForm.teamClass" placeholder="请选择队别班次" clearable filterable class="shift-select">
v-model="shiftXydbh" <el-option v-for="item in teamClassOptions" :key="item" :label="item" :value="item" />
placeholder="请选择队别班次"
clearable
filterable
class="shift-select"
>
<el-option v-for="t in teamOptions" :key="t.xydbh" :label="t.xydmc" :value="t.xydbh" />
</el-select>
</el-form-item>
<el-form-item label="年度">
<el-select v-model="shiftNd" placeholder="请选择年度" class="shift-select">
<el-option v-for="y in yearOptions" :key="y" :label="y" :value="y" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleShiftSearch">查询</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">查询</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div>
<!-- 标题 --> <!-- 标题 -->
<div class="shift-title">{{ shiftTitle }}</div> <div class="page-title">{{ pageTitle }}</div>
<!-- 操作按钮 --> <!-- 下载操作按钮 -->
<el-row :gutter="10" class="mb8"> <el-card shadow="never" class="action-card">
<el-col :span="1.5"> <div class="button-row">
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleNotProvided">学期教学实施计划</el-button> <el-button type="primary" plain size="mini" @click="handleExportPlan">学期教学实施计划</el-button>
</el-col> <el-button type="primary" plain size="mini" @click="handleExportGrades">学期成绩表</el-button>
<el-col :span="1.5"> <el-button type="primary" plain size="mini" @click="handleExportCourses">课程列表另存Excel</el-button>
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleNotProvided">学期课程表周次星期</el-button> </div>
</el-col> </el-card>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleNotProvided">学期课程表班次视图</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleNotProvided">学期课程表排课周含选修</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleNotProvided">学期教学实施计划含选修</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleNotProvided">学期课程表周次星期详细</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleNotProvided">学期成绩表</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-download" size="mini" @click="handleNotProvided">课程列表另存Excel</el-button>
</el-col>
</el-row>
<!-- 班次课程表 --> <!-- 数据表格 -->
<div class="table-card"> <div class="table-card">
<el-table v-loading="shiftLoading" :data="shiftList" border stripe> <el-table :data="shiftData" v-loading="loading" border stripe style="width: 100%">
<el-table-column type="index" label="序号" width="60" align="center" /> <el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="课程名称/简称" min-width="200" header-align="center"> <el-table-column label="课程名称/课时系数" min-width="220" header-align="center">
<template slot-scope="scope"> <template #default="{ row }">
<div>{{ scope.row._kcmc || '-' }}</div> <div>{{ row.kcmc || '-' }}</div>
<div class="sub-text">{{ scope.row.jc || '-' }}</div> <div class="sub-text">{{ row.kssk || '-' }}</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="责任教员/课次" width="160" header-align="center"> <el-table-column prop="zrjs" label="责任教员/课次" min-width="150" show-overflow-tooltip header-align="center" />
<template slot-scope="scope"> <el-table-column prop="bc" label="班次" min-width="120" show-overflow-tooltip header-align="center" />
<div>{{ scope.row._zrjy || '-' }}</div> <el-table-column prop="nj" label="年级" width="80" align="center" />
<div class="sub-text">{{ scope.row.kcxh || '-' }}次课</div> <el-table-column prop="zy" label="专业" min-width="120" show-overflow-tooltip header-align="center" />
</template> <el-table-column prop="jhxs" label="计划学时" width="90" align="center" />
</el-table-column> <el-table-column prop="yxxs" label="运行学时" width="90" align="center" />
<el-table-column prop="xydmc" label="班次" width="130" show-overflow-tooltip header-align="center" /> <el-table-column prop="khlxfs" label="考核类型方式" min-width="140" show-overflow-tooltip header-align="center" />
<el-table-column prop="xs" label="计划学时" width="90" align="center" /> <el-table-column prop="ssjs" label="实施教员" min-width="120" show-overflow-tooltip header-align="center" />
<el-table-column prop="llxs" label="理论学时" width="90" align="center" /> <el-table-column prop="rscd" label="人数/场地" min-width="140" show-overflow-tooltip header-align="center" />
<el-table-column prop="sjxs" label="实践学时" width="90" align="center" /> <el-table-column prop="kcjd" label="课程进度" width="120" align="center" />
<el-table-column prop="cjfz" label="考核类型方式" min-width="110" show-overflow-tooltip header-align="center" /> <el-table-column prop="ssjhbg" label="实施计划变更" min-width="120" align="center" show-overflow-tooltip />
<el-table-column label="实施教员" width="110" align="center" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row._ssjy || '-' }}</template>
</el-table-column>
<el-table-column label="人数/场地" width="130" header-align="center">
<template slot-scope="scope">
<div>{{ scope.row.rs || '-' }} </div>
<div class="sub-text">{{ scope.row.jsbh || '-' }}</div>
</template>
</el-table-column>
<el-table-column prop="xf" label="学分" width="80" align="center" />
<el-table-column label="实施计划变更" width="150" header-align="center">
<template slot-scope="scope">{{ fmtKbbdsj(scope.row.kbbdsj) }}</template>
</el-table-column>
</el-table> </el-table>
<el-empty v-show="!shiftLoading && !shiftList.length" description="该班次暂无课程数据" /> <el-empty v-show="!loading && !shiftData.length" description="请选择队别班次后查询" />
<pagination
v-show="shiftTotal > 0"
:total="shiftTotal"
:page.sync="shiftQuery.pageNum"
:limit.sync="shiftQuery.pageSize"
@pagination="getShiftList"
/>
</div> </div>
</div> </div>
</el-tab-pane> </el-tab-pane>
@@ -231,14 +129,9 @@
</template> </template>
<script> <script>
import { listTeachingPlan } from '@/api/teachBusiness/courseRunning' import { listToday, listWeek, listClass, exportClassPlan, exportClassGrades, exportClassCourses } from '@/api/teachBusiness/timetable'
import { listStudentTeamTask } from '@/api/teachBusiness/studentTeamTask'
import { listTeam } from '@/api/studentRecords/team' import { listTeam } from '@/api/studentRecords/team'
import { listKb } from '@/api/teachOffice/kb'
import { listTeacher } from '@/api/teachOffice/teacher'
import { listAllSemester } from '@/api/teachBusiness/semester'
// 节次 -> 节次区间映射
const JC_SECTION = { const JC_SECTION = {
1: '1-2节', 2: '3-4节', 3: '5-6节', 4: '7-8节', 5: '9-10节', 6: '11-12节' 1: '1-2节', 2: '3-4节', 3: '5-6节', 4: '7-8节', 5: '9-10节', 6: '11-12节'
} }
@@ -265,124 +158,49 @@ export default {
data() { data() {
return { return {
activeTab: 'today', activeTab: 'today',
loading: false,
// 今日 // 今日
todayDate: new Date(), todayDate: new Date(),
todayList: [], todayData: [],
todayLoading: false,
// 本周 // 本周
weekStart: getMonday(new Date()), weekStart: getMonday(new Date()),
weekList: [], weekData: [],
weekLoading: false,
weekTotal: 0,
weekQuery: { pageNum: 1, pageSize: 20 },
// 三实
practiceStart: getMonday(new Date()),
practiceList: [],
practiceLoading: false,
practiceTotal: 0,
practiceQuery: { pageNum: 1, pageSize: 20 },
// 班次 // 班次
teamOptions: [], searchForm: { teamClass: '' },
shiftXydbh: '', teamClassOptions: [],
shiftNd: undefined, teamMap: {},
shiftList: [], shiftData: []
shiftLoading: false,
shiftTotal: 0,
shiftQuery: { pageNum: 1, pageSize: 20 },
// 年度下拉数据来自 /semester/all(真实后端数据)
yearOptions: [],
defaultNd: undefined,
// 名称映射(真实接口数据,用于班次 tab 课程/教员编号转名称)
kbMap: {},
teacherMap: {}
} }
}, },
computed: { computed: {
todayTitle() { dateTitle() {
return '当前日期:' + formatDate(this.todayDate) + '时间顺序教学实施计划' return formatDate(this.todayDate) + ' 今日教学实施计划'
}, },
weekTitle() { weekRangeText() {
const end = new Date(this.weekStart) const end = new Date(this.weekStart)
end.setDate(end.getDate() + 6) end.setDate(end.getDate() + 6)
return formatDate(this.weekStart) + '(' + this.weekDayName(this.weekStart) + ') 至 ' + return formatDate(this.weekStart) + '(' + this.weekDayName(this.weekStart) + ') 至 ' +
formatDate(end) + '(' + this.weekDayName(end) + ') 教学实施计划' formatDate(end) + '(' + this.weekDayName(end) + ') 本周教学实施计划'
}, },
practiceTitle() { pageTitle() {
const end = new Date(this.practiceStart) const name = this.searchForm.teamClass || ''
end.setDate(end.getDate() + 6) return (name ? name + ' ' : '') + '教学班次教学实施计划'
return formatDate(this.practiceStart) + '(' + this.weekDayName(this.practiceStart) + ') 至 ' +
formatDate(end) + '(' + this.weekDayName(end) + ') 三实教学实施计划'
},
shiftTitle() {
const team = this.teamOptions.find(t => t.xydbh === this.shiftXydbh)
const name = (team && team.xydmc) || ''
return (this.shiftNd ? this.shiftNd + '年' : '') + name + '课程表'
} }
}, },
created() { created() {
this.loadYearOptions() this.loadTeamOptions()
this.getTodayList() this.getTodayList()
this.getWeekList() this.getWeekList()
this.getPracticeList()
this.loadTeamOptions()
this.loadKbMap()
this.loadTeacherMap()
}, },
methods: { methods: {
/* ---------- 年度下拉(数据来自 /semester/all ---------- */
loadYearOptions() {
return listAllSemester().then(response => {
const list = response.data || []
// 去重并按年度倒序
const map = {}
list.forEach(item => {
if (item.nd !== null && item.nd !== undefined && item.nd !== '') map[item.nd] = item
})
const arr = Object.keys(map).sort((a, b) => String(b).localeCompare(String(a)))
this.yearOptions = arr
// 默认年度:优先当前学期(dqxq=true),否则取最新年度
const current = list.find(item => item.dqxq === true)
this.defaultNd = (current && current.nd) || arr[0]
if (!this.shiftNd) this.shiftNd = this.defaultNd
return arr
}).catch(() => {
this.yearOptions = []
this.defaultNd = undefined
return []
})
},
weekDayName(d) { weekDayName(d) {
return WEEK_DAY_NAMES[d.getDay()] return WEEK_DAY_NAMES[d.getDay()]
}, },
formatSection(jc) { formatJc(jc) {
if (jc === null || jc === undefined || jc === '') return '第?节' if (jc === null || jc === undefined || jc === '') return '第?节'
return JC_SECTION[jc] || ('第' + jc + '节') return JC_SECTION[jc] || ('第' + jc + '节')
}, },
/** 后端 LocalDateTime -> 日期+周X+节次区间 */ /* ---------- 今日:日期导航 ---------- */
fmtLessonTime(row) {
const rq = row.rq || ''
const date = String(rq).substring(0, 10)
if (!date) return '-'
const d = new Date(date.replace(/-/g, '/'))
const wn = WEEK_DAY_NAMES[d.getDay()]
return (date + ' 周' + wn + ' ' + this.formatSection(row.jc)).trim()
},
/** 后端 LocalDateTime -> yyyy-MM-dd HH:mm */
fmtKbbdsj(v) {
if (!v) return '-'
return String(v).replace('T', ' ').substring(0, 16)
},
txztText(txzt) {
if (txzt === 1) return '已填写'
if (txzt === 2) return '已提交'
return '未填写'
},
txztType(txzt) {
if (txzt === 1) return 'success'
if (txzt === 2) return 'primary'
return 'info'
},
/* ---------- 今日 ---------- */
handlePrevDay() { handlePrevDay() {
const d = new Date(this.todayDate) const d = new Date(this.todayDate)
d.setDate(d.getDate() - 1) d.setDate(d.getDate() - 1)
@@ -395,179 +213,163 @@ export default {
this.todayDate = d this.todayDate = d
this.getTodayList() this.getTodayList()
}, },
getTodayList() { /* ---------- 本周:周次导航 ---------- */
const day = formatDate(this.todayDate)
const params = {
rqStart: day + 'T00:00:00',
rqEnd: day + 'T23:59:59',
pageNum: 1,
pageSize: 200
}
this.todayLoading = true
listTeachingPlan(params).then(response => {
const data = response.data || {}
this.todayList = data.records || []
this.todayLoading = false
}).catch(() => {
this.todayList = []
this.todayLoading = false
})
},
/* ---------- 本周 ---------- */
handlePrevWeek() { handlePrevWeek() {
const d = new Date(this.weekStart) const d = new Date(this.weekStart)
d.setDate(d.getDate() - 7) d.setDate(d.getDate() - 7)
this.weekStart = d this.weekStart = d
this.weekQuery.pageNum = 1
this.getWeekList() this.getWeekList()
}, },
handleNextWeek() { handleNextWeek() {
const d = new Date(this.weekStart) const d = new Date(this.weekStart)
d.setDate(d.getDate() + 7) d.setDate(d.getDate() + 7)
this.weekStart = d this.weekStart = d
this.weekQuery.pageNum = 1
this.getWeekList() this.getWeekList()
}, },
weekRange() { /* ---------- 队别班次下拉(真实接口) ---------- */
const start = formatDate(this.weekStart) + 'T00:00:00'
const endDate = new Date(this.weekStart)
endDate.setDate(endDate.getDate() + 6)
const end = formatDate(endDate) + 'T23:59:59'
return { start: start, end: end }
},
getWeekList() {
const range = this.weekRange()
const params = {
rqStart: range.start,
rqEnd: range.end,
pageNum: this.weekQuery.pageNum,
pageSize: this.weekQuery.pageSize
}
this.weekLoading = true
listTeachingPlan(params).then(response => {
const data = response.data || {}
this.weekList = data.records || []
this.weekTotal = data.total || 0
this.weekLoading = false
}).catch(() => {
this.weekList = []
this.weekTotal = 0
this.weekLoading = false
})
},
/* ---------- 三实 ---------- */
handlePrevWeek3() {
const d = new Date(this.practiceStart)
d.setDate(d.getDate() - 7)
this.practiceStart = d
this.practiceQuery.pageNum = 1
this.getPracticeList()
},
handleNextWeek3() {
const d = new Date(this.practiceStart)
d.setDate(d.getDate() + 7)
this.practiceStart = d
this.practiceQuery.pageNum = 1
this.getPracticeList()
},
practiceRange() {
const start = formatDate(this.practiceStart) + 'T00:00:00'
const endDate = new Date(this.practiceStart)
endDate.setDate(endDate.getDate() + 6)
const end = formatDate(endDate) + 'T23:59:59'
return { start: start, end: end }
},
getPracticeList() {
// 后端 plan/list 接口未返回课程类型字段,无法按三实课筛选,与本周共用同一数据源
const range = this.practiceRange()
const params = {
rqStart: range.start,
rqEnd: range.end,
pageNum: this.practiceQuery.pageNum,
pageSize: this.practiceQuery.pageSize
}
this.practiceLoading = true
listTeachingPlan(params).then(response => {
const data = response.data || {}
this.practiceList = data.records || []
this.practiceTotal = data.total || 0
this.practiceLoading = false
}).catch(() => {
this.practiceList = []
this.practiceTotal = 0
this.practiceLoading = false
})
},
/* ---------- 班次 ---------- */
loadTeamOptions() { loadTeamOptions() {
listTeam({ pageNum: 1, pageSize: 1000 }).then(response => { listTeam({ pageNum: 1, pageSize: 1000 }).then(response => {
const data = response.data || {} const data = response.data || {}
this.teamOptions = data.records || [] const list = data.records || []
}).catch(() => {
this.teamOptions = []
})
},
loadKbMap() {
listKb({ pageNum: 1, pageSize: 1000 }).then(response => {
const data = response.data || {}
const map = {} const map = {}
;(data.records || []).forEach(item => { ;(list || []).forEach(item => {
if (item.kbh) map[item.kbh] = item.kmc if (item.xydmc) map[item.xydmc] = item.xydbh
}) })
this.kbMap = map this.teamMap = map
this.teamClassOptions = list.map(item => item.xydmc).filter(Boolean)
}).catch(() => { }).catch(() => {
this.kbMap = {} this.teamMap = {}
this.teamClassOptions = []
}) })
}, },
loadTeacherMap() { /* ---------- 数据字段映射(接口字段 -> 页面字段) ---------- */
listTeacher({ pageNum: 1, pageSize: 1000 }).then(response => { parseSection(sksj) {
const m = String(sksj || '').match(/第(\d+)节/)
return m ? Number(m[1]) : undefined
},
mapLessonRow(apiRow) {
// 接口今日/本周实体:bh sksj kc zrdw bc jy cd jxnrxff bz
const row = Object.assign({}, apiRow)
row.kcmc = apiRow.kc
row.skjy = apiRow.jy
row.jxcd = apiRow.cd
row.jxnrff = apiRow.jxnrxff
row.jybz = apiRow.bz
row.sjsj = apiRow.sksj
row.jc = this.parseSection(apiRow.sksj)
return row
},
mapClassRow(apiRow) {
// 接口班次实体:sskcbh kcmcksxs zrjykc jhxs yxxs khlxfs ssjy rscd ssjhbg
const row = Object.assign({}, apiRow)
const parts = String(apiRow.kcmcksxs || '').split(' / ')
row.kcmc = parts[0] || '-'
row.kssk = parts[1] || '-'
row.zrjs = apiRow.zrjykc
row.ssjs = apiRow.ssjy
return row
},
/* ---------- 今日:拉取数据 ---------- */
getTodayList() {
this.loading = true
listToday({}).then(response => {
const data = response.data
this.todayData = Array.isArray(data)
? (data || []).map(item => this.mapLessonRow(item))
: ((data && data.records) || []).map(item => this.mapLessonRow(item))
this.loading = false
}).catch(() => {
this.todayData = []
this.loading = false
})
},
/* ---------- 本周:拉取数据 ---------- */
getWeekList() {
this.loading = true
listWeek({}).then(response => {
const data = response.data
this.weekData = Array.isArray(data)
? (data || []).map(item => this.mapLessonRow(item))
: ((data && data.records) || []).map(item => this.mapLessonRow(item))
this.loading = false
}).catch(() => {
this.weekData = []
this.loading = false
})
},
/* ---------- 班次:拉取数据 ---------- */
getShiftList() {
if (!this.searchForm.teamClass) return
const xydbh = this.teamMap[this.searchForm.teamClass] || this.searchForm.teamClass
const params = { xydbh: xydbh, pageNum: 1, pageSize: 1000 }
this.loading = true
listClass(params).then(response => {
const data = response.data || {} const data = response.data || {}
const map = {} this.shiftData = (data.records || []).map(item => this.mapClassRow(item))
;(data.records || []).forEach(item => { this.loading = false
if (item.jybh) map[item.jybh] = item.jyxm
})
this.teacherMap = map
}).catch(() => { }).catch(() => {
this.teacherMap = {} this.shiftData = []
this.loading = false
}) })
}, },
handleShiftSearch() { /* ---------- 班次:查询 ---------- */
if (!this.shiftXydbh) { handleQuery() {
if (!this.searchForm.teamClass) {
this.$message.warning('请先选择队别班次') this.$message.warning('请先选择队别班次')
return return
} }
this.shiftQuery.pageNum = 1
this.getShiftList() this.getShiftList()
}, },
getShiftList() { /* ---------- 下载 ---------- */
const params = { downloadBlob(blob, filename) {
xydbh: this.shiftXydbh, const link = document.createElement('a')
nd: this.shiftNd, link.href = window.URL.createObjectURL(blob)
pageNum: this.shiftQuery.pageNum, link.download = filename
pageSize: this.shiftQuery.pageSize document.body.appendChild(link)
} link.click()
this.shiftLoading = true document.body.removeChild(link)
listStudentTeamTask(params).then(response => { window.URL.revokeObjectURL(link.href)
const data = response.data || {}
const team = this.teamOptions.find(t => t.xydbh === this.shiftXydbh)
this.shiftList = (data.records || []).map(item => ({
...item,
xydmc: (team && team.xydmc) || item.xydbh,
_kcmc: this.kbMap[item.kbh] || item.kbh,
_zrjy: this.teacherMap[item.jysjhjybh] || item.jysjhjybh || '-',
_ssjy: this.teacherMap[item.jybh] || item.jybh || '-'
}))
this.shiftTotal = data.total || 0
this.shiftLoading = false
}).catch(() => {
this.shiftList = []
this.shiftTotal = 0
this.shiftLoading = false
})
}, },
/* ---------- 无后端接口的操作 ---------- */ shiftQueryParams() {
handleNotProvided() { if (!this.searchForm.teamClass) return null
this.$message.info('后端暂未提供该接口') const xydbh = this.teamMap[this.searchForm.teamClass] || this.searchForm.teamClass
return { xydbh: xydbh }
},
/** 下载学期教学实施计划 ExcelGET /kcb/class/export-plan */
handleExportPlan() {
const params = this.shiftQueryParams()
if (!params) {
this.$message.warning('请先选择队别班次')
return
}
exportClassPlan(params).then(blob => {
this.downloadBlob(blob, '学期教学实施计划.xlsx')
this.$message.success('学期教学实施计划导出成功')
}).catch(() => {})
},
/** 下载学期成绩表 ExcelGET /kcb/class/export-grades */
handleExportGrades() {
const params = this.shiftQueryParams()
if (!params) {
this.$message.warning('请先选择队别班次')
return
}
exportClassGrades(params).then(blob => {
this.downloadBlob(blob, '学期成绩表.xlsx')
this.$message.success('学期成绩表导出成功')
}).catch(() => {})
},
/** 班次课程列表另存 ExcelGET /kcb/class/export-courses */
handleExportCourses() {
const params = this.shiftQueryParams()
if (!params) {
this.$message.warning('请先选择队别班次')
return
}
exportClassCourses(params).then(blob => {
this.downloadBlob(blob, '班次课程列表.xlsx')
this.$message.success('班次课程列表导出成功')
}).catch(() => {})
} }
} }
} }
@@ -586,12 +388,15 @@ export default {
padding-bottom: 16px; padding-bottom: 16px;
} }
.mb8 { .sub-text {
margin-bottom: 8px; font-size: 12px;
color: #909399;
margin-top: 2px;
} }
/* 日期/周次导航 */ /* 日期/周次导航 */
.nav-header { .date-header,
.week-header {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -606,30 +411,28 @@ export default {
font-size: 14px; font-size: 14px;
} }
.nav-title { .date-title,
font-size: 18px; .week-title {
font-size: 16px;
font-weight: 700; font-weight: 700;
color: #303133; color: #303133;
} }
} }
/* 表格区 */
.table-card {
.danger-text {
color: #f56c6c;
}
}
/* 班次 */ /* 班次 */
.shift-search { .search-card {
margin-bottom: 8px; margin-bottom: 12px;
.search-form {
margin-bottom: 0;
} }
.shift-select { .shift-select {
width: 220px; width: 240px;
}
} }
.shift-title { .page-title {
font-size: 17px; font-size: 17px;
font-weight: 700; font-weight: 700;
color: #303133; color: #303133;
@@ -637,10 +440,14 @@ export default {
margin-bottom: 12px; margin-bottom: 12px;
} }
.sub-text { .action-card {
font-size: 12px; margin-bottom: 12px;
color: #909399;
margin-top: 2px; .button-row {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
} }
} }
</style> </style>