forked from liweijie/education
Merge branch 'main' of https://gitea.fengyingkj.top/zhaichao/education
This commit is contained in:
@@ -0,0 +1,589 @@
|
||||
<template>
|
||||
<div class="app-container syllabus-page">
|
||||
<!-- 查询条件 -->
|
||||
<el-card shadow="never" class="search-card">
|
||||
<el-form :model="searchForm" label-width="100px" class="search-form" @submit.native.prevent>
|
||||
<el-row :gutter="32">
|
||||
<el-col :xs="24" :md="8">
|
||||
<el-form-item label="专业代号">
|
||||
<el-input v-model="searchForm.zydh" placeholder="请输入专业代号" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="8">
|
||||
<el-form-item label="停用">
|
||||
<el-radio-group v-model="searchForm.ty">
|
||||
<el-radio :label="0">否</el-radio>
|
||||
<el-radio :label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="8">
|
||||
<div class="search-actions">
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 数据列表 -->
|
||||
<el-card shadow="never" class="table-card">
|
||||
<div class="list-header">
|
||||
<div class="list-title">教学大纲列表</div>
|
||||
<div class="list-actions">
|
||||
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
:disabled="!selection.length"
|
||||
@click="handleBatchDelete"
|
||||
>删除所选</el-button>
|
||||
<el-button icon="el-icon-download" @click="handleDownload">下载</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table v-loading="loading" :data="pagedData" border stripe highlight-current-row
|
||||
@selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="50" align="center" />
|
||||
<el-table-column prop="bh" label="编号" width="170" show-overflow-tooltip align="center" />
|
||||
<el-table-column prop="zydh" label="专业代号" width="150" align="center" />
|
||||
<el-table-column prop="kbh" label="课编号" width="110" show-overflow-tooltip align="center" />
|
||||
<el-table-column prop="jc" label="简称" width="100" show-overflow-tooltip align="center" />
|
||||
<el-table-column prop="klx" label="课类型" width="80" align="center" />
|
||||
<el-table-column prop="xqdc" label="学期第次" width="80" align="center" />
|
||||
<el-table-column prop="xs" label="学时" width="70" align="center" />
|
||||
<el-table-column prop="xf" label="学分" width="70" align="center" />
|
||||
<el-table-column prop="llxs" label="理论学时" width="80" align="center" />
|
||||
<el-table-column prop="sjxs" label="实践学时" width="80" align="center" />
|
||||
<el-table-column prop="zks" label="周课时" width="70" align="center" />
|
||||
<el-table-column prop="ksks" label="考试课时" width="80" align="center" />
|
||||
<el-table-column label="大纲课程" width="90" align="center">
|
||||
<template slot-scope="scope">{{ fmtYesNo(scope.row.dgkc) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="停用" width="80" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="Number(scope.row.ty) === 1 ? 'danger' : 'success'" size="mini">
|
||||
{{ Number(scope.row.ty) === 1 ? '停用' : '正常' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="启用时间" width="150" align="center">
|
||||
<template slot-scope="scope">{{ fmtDateTime(scope.row.qysj) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="停用时间" width="150" align="center">
|
||||
<template slot-scope="scope">{{ fmtDateTime(scope.row.tysj) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="160" align="center" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" icon="el-icon-delete" class="danger-text-btn" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
background
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:current-page="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 新增/编辑弹窗 -->
|
||||
<el-dialog :title="dialog.title" :visible.sync="dialog.visible" width="720px" append-to-body
|
||||
:close-on-click-modal="false">
|
||||
<el-form ref="syllabusForm" :model="dialog.form" :rules="rules" label-width="130px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="专业" prop="zydh">
|
||||
<el-select
|
||||
v-model="dialog.form.zydh"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择专业"
|
||||
class="w-full"
|
||||
:loading="referenceDataLoading"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in majorOptions"
|
||||
:key="item.zydh"
|
||||
:label="item.zymc"
|
||||
:value="item.zydh"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="课程" prop="kbh">
|
||||
<el-select
|
||||
v-model="dialog.form.kbh"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择课程"
|
||||
class="w-full"
|
||||
:loading="referenceDataLoading"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in subjectOptions"
|
||||
:key="item.kbh"
|
||||
:label="item.kmc"
|
||||
:value="item.kbh"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="学期第次" prop="xqdc">
|
||||
<el-input-number v-model="dialog.form.xqdc" :min="1" :max="20" controls-position="right" class="w-full" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="课类型" prop="klx">
|
||||
<el-select
|
||||
v-model="dialog.form.klx"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择课类型"
|
||||
class="w-full"
|
||||
:loading="referenceDataLoading"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in courseTypeOptions"
|
||||
:key="item.dictValue"
|
||||
:label="item.dictLabel"
|
||||
:value="item.dictValue"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="学时" prop="xs">
|
||||
<el-input-number v-model="dialog.form.xs" :min="0" controls-position="right" class="w-full" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="停用" prop="ty">
|
||||
<el-radio-group v-model="dialog.form.ty">
|
||||
<el-radio :label="0">否</el-radio>
|
||||
<el-radio :label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="简称">
|
||||
<el-input v-model="dialog.form.jc" placeholder="请输入课程简称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="学分">
|
||||
<el-input-number v-model="dialog.form.xf" :min="0" :step="0.5" :precision="1" controls-position="right" class="w-full" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="课程定位">
|
||||
<el-input v-model="dialog.form.kcdw" placeholder="请输入课程定位" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="模块">
|
||||
<el-input v-model="dialog.form.mk" placeholder="请输入模块" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="成绩分制">
|
||||
<el-input v-model="dialog.form.cjfz" placeholder="请输入成绩分制" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="教研室">
|
||||
<el-select
|
||||
v-model="dialog.form.jysdh"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择教研室"
|
||||
class="w-full"
|
||||
:loading="referenceDataLoading"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in officeOptions"
|
||||
:key="item.jysdh"
|
||||
:label="item.jysmc"
|
||||
:value="item.jysdh"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="考试课时">
|
||||
<el-input-number v-model="dialog.form.ksks" :min="0" controls-position="right" class="w-full" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="理论学时">
|
||||
<el-input-number v-model="dialog.form.llxs" :min="0" controls-position="right" class="w-full" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="实践学时">
|
||||
<el-input-number v-model="dialog.form.sjxs" :min="0" controls-position="right" class="w-full" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="周课时">
|
||||
<el-input-number v-model="dialog.form.zks" :min="0" controls-position="right" class="w-full" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="不计入平均分">
|
||||
<el-radio-group v-model="dialog.form.bjrxypjf">
|
||||
<el-radio :label="0">否</el-radio>
|
||||
<el-radio :label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="考试课时不显示">
|
||||
<el-radio-group v-model="dialog.form.ksksbxs">
|
||||
<el-radio :label="0">否</el-radio>
|
||||
<el-radio :label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="大纲课程">
|
||||
<el-radio-group v-model="dialog.form.dgkc">
|
||||
<el-radio :label="0">否</el-radio>
|
||||
<el-radio :label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialog.visible = false">取 消</el-button>
|
||||
<el-button type="primary" :loading="dialog.submitting" @click="submitDialog">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
addSyllabus,
|
||||
deleteSyllabus,
|
||||
batchDeleteSyllabus,
|
||||
updateSyllabus,
|
||||
listSyllabus,
|
||||
listSyllabusByZydhAndTy
|
||||
} from '@/api/teachBusiness/syllabus'
|
||||
import { listMajor } from '@/api/subjectMajor/major'
|
||||
import { listKb } from '@/api/teachOffice/kb'
|
||||
import { listOffice } from '@/api/teachOffice/office'
|
||||
import { getDicts } from '@/api/system/dict/data'
|
||||
|
||||
const REFERENCE_DATA_PAGE_SIZE = 10000
|
||||
const COURSE_TYPE_DICT_CODE = 'course_type'
|
||||
|
||||
export default {
|
||||
name: 'SyllabusIndex',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
searchForm: {
|
||||
zydh: '',
|
||||
ty: 0
|
||||
},
|
||||
tableData: [],
|
||||
total: 0,
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
selection: [],
|
||||
referenceDataLoading: false,
|
||||
majorOptions: [],
|
||||
subjectOptions: [],
|
||||
courseTypeOptions: [],
|
||||
officeOptions: [],
|
||||
dialog: {
|
||||
visible: false,
|
||||
title: '',
|
||||
submitting: false,
|
||||
form: this.createEmptyForm()
|
||||
},
|
||||
rules: {
|
||||
zydh: [{ required: true, message: '请选择专业', trigger: 'change' }],
|
||||
kbh: [{ required: true, message: '请选择课程', trigger: 'change' }],
|
||||
xqdc: [{ required: true, message: '请输入学期第次', trigger: 'blur' }],
|
||||
klx: [{ required: true, message: '请选择课类型', trigger: 'change' }],
|
||||
xs: [{ required: true, message: '请输入学时', trigger: 'blur' }],
|
||||
ty: [{ required: true, message: '请选择停用标识', trigger: 'change' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
pagedData() {
|
||||
const start = (this.pageNum - 1) * this.pageSize
|
||||
return this.tableData.slice(start, start + this.pageSize)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchList()
|
||||
this.loadReferenceData()
|
||||
},
|
||||
methods: {
|
||||
loadReferenceData() {
|
||||
this.referenceDataLoading = true
|
||||
const query = { pageNum: 1, pageSize: REFERENCE_DATA_PAGE_SIZE }
|
||||
const requests = [
|
||||
listMajor(query),
|
||||
listKb(query),
|
||||
listOffice(query),
|
||||
getDicts(COURSE_TYPE_DICT_CODE)
|
||||
].map(request => {
|
||||
return request
|
||||
.then(response => this.getResponseRecords(response))
|
||||
.catch(() => [])
|
||||
})
|
||||
|
||||
Promise.all(requests).then(([majors, subjects, offices, courseTypes]) => {
|
||||
this.majorOptions = this.getUniqueOptions(majors, 'zydh', 'zymc')
|
||||
this.subjectOptions = this.getUniqueOptions(subjects, 'kbh', 'kmc')
|
||||
this.officeOptions = this.getUniqueOptions(offices, 'jysdh', 'jysmc')
|
||||
this.courseTypeOptions = this.getUniqueOptions(courseTypes, 'dictValue', 'dictLabel')
|
||||
}).finally(() => {
|
||||
this.referenceDataLoading = false
|
||||
})
|
||||
},
|
||||
getResponseRecords(response) {
|
||||
const data = response.data || {}
|
||||
|
||||
return Array.isArray(data) ? data : data.records || []
|
||||
},
|
||||
getUniqueOptions(items, valueKey, labelKey) {
|
||||
const values = new Set()
|
||||
|
||||
return items.filter(item => {
|
||||
const value = item[valueKey]
|
||||
const label = item[labelKey]
|
||||
if (!value || !label || values.has(value)) {
|
||||
return false
|
||||
}
|
||||
values.add(value)
|
||||
|
||||
return true
|
||||
})
|
||||
},
|
||||
/* ---------- 列表加载 ---------- */
|
||||
fetchList() {
|
||||
this.loading = true
|
||||
const { zydh, ty } = this.searchForm
|
||||
// 专业代号存在时走后端组合查询;否则查全部后按停用标识过滤
|
||||
const useApiQuery = Boolean(zydh)
|
||||
const req = useApiQuery
|
||||
? listSyllabusByZydhAndTy(zydh, ty)
|
||||
: listSyllabus()
|
||||
req.then(response => {
|
||||
let list = response.data || []
|
||||
if (!useApiQuery) {
|
||||
if (zydh) list = list.filter(i => i.zydh && i.zydh.indexOf(zydh) !== -1)
|
||||
list = list.filter(i => Number(i.ty) === Number(ty))
|
||||
}
|
||||
this.tableData = list
|
||||
this.total = list.length
|
||||
this.pageNum = 1
|
||||
}).catch(() => {
|
||||
this.tableData = []
|
||||
this.total = 0
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleQuery() {
|
||||
this.fetchList()
|
||||
},
|
||||
handleReset() {
|
||||
this.searchForm = { zydh: '', ty: 0 }
|
||||
this.fetchList()
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.selection = val
|
||||
},
|
||||
|
||||
/* ---------- 新增 / 编辑 ---------- */
|
||||
handleAdd() {
|
||||
this.dialog.title = '新增教学大纲'
|
||||
this.dialog.form = this.createEmptyForm()
|
||||
this.dialog.visible = true
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.syllabusForm) this.$refs.syllabusForm.clearValidate()
|
||||
})
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.dialog.title = '编辑教学大纲'
|
||||
this.dialog.form = Object.assign({}, this.createEmptyForm(), row)
|
||||
this.dialog.visible = true
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.syllabusForm) this.$refs.syllabusForm.clearValidate()
|
||||
})
|
||||
},
|
||||
submitDialog() {
|
||||
this.$refs.syllabusForm.validate(valid => {
|
||||
if (!valid) return
|
||||
this.dialog.submitting = true
|
||||
const payload = this.cleanPayload(this.dialog.form)
|
||||
const isEdit = !!payload.bh
|
||||
const req = isEdit ? updateSyllabus(payload) : addSyllabus(payload)
|
||||
req.then(() => {
|
||||
this.$message.success(isEdit ? '修改成功' : '新增成功')
|
||||
this.dialog.visible = false
|
||||
this.fetchList()
|
||||
}).finally(() => {
|
||||
this.dialog.submitting = false
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
/* ---------- 删除 / 批量删除 ---------- */
|
||||
handleDelete(row) {
|
||||
this.$confirm('删除后该条记录将置为「停用」,是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
return deleteSyllabus(row.bh)
|
||||
}).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.fetchList()
|
||||
}).catch(() => {})
|
||||
},
|
||||
handleBatchDelete() {
|
||||
if (!this.selection.length) {
|
||||
this.$message.warning('请先勾选要删除的记录')
|
||||
return
|
||||
}
|
||||
const bhList = this.selection.map(row => row.bh)
|
||||
this.$confirm('确定删除所选 ' + bhList.length + ' 条记录吗?(将置为「停用」)', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
return batchDeleteSyllabus(bhList)
|
||||
}).then(() => {
|
||||
this.$message.success('批量删除成功')
|
||||
this.fetchList()
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
/* ---------- 下载(无后端接口) ---------- */
|
||||
handleDownload() {
|
||||
this.$message.warning('后端暂未提供该接口')
|
||||
},
|
||||
|
||||
/* ---------- 分页 ---------- */
|
||||
handleSizeChange(size) {
|
||||
this.pageSize = size
|
||||
this.pageNum = 1
|
||||
},
|
||||
handlePageChange(page) {
|
||||
this.pageNum = page
|
||||
},
|
||||
|
||||
/* ---------- 工具 ---------- */
|
||||
createEmptyForm() {
|
||||
return {
|
||||
bh: '',
|
||||
zydh: '',
|
||||
kbh: '',
|
||||
xqdc: 1,
|
||||
klx: '',
|
||||
xs: 0,
|
||||
ty: 0,
|
||||
jc: '',
|
||||
xf: null,
|
||||
kcdw: '',
|
||||
ksks: 0,
|
||||
mk: '',
|
||||
cjfz: '',
|
||||
bjrxypjf: 0,
|
||||
llxs: 0,
|
||||
sjxs: 0,
|
||||
zks: 0,
|
||||
ksksbxs: 0,
|
||||
dgkc: 0,
|
||||
jysdh: ''
|
||||
}
|
||||
},
|
||||
/** 移除空值(''/null/undefined),保留 0 等有效值 */
|
||||
cleanPayload(obj) {
|
||||
const payload = {}
|
||||
Object.keys(obj).forEach(key => {
|
||||
const value = obj[key]
|
||||
if (value !== '' && value !== null && value !== undefined) {
|
||||
payload[key] = value
|
||||
}
|
||||
})
|
||||
return payload
|
||||
},
|
||||
fmtYesNo(val) {
|
||||
return Number(val) === 1 ? '是' : '否'
|
||||
},
|
||||
fmtDateTime(val) {
|
||||
return (val || '').substring(0, 16) || '-'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.app-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.syllabus-page {
|
||||
.search-card {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.search-form {
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-actions {
|
||||
padding-top: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-card {
|
||||
.list-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.list-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: 16px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.danger-text-btn {
|
||||
color: #f56c6c;
|
||||
|
||||
&:hover {
|
||||
color: #f78989;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,466 @@
|
||||
<template>
|
||||
<div class="app-container timetable-page">
|
||||
<el-tabs v-model="activeTab" class="timetable-tabs">
|
||||
<!-- ==================== 今日教学实施计划 ==================== -->
|
||||
<el-tab-pane label="今日教学实施计划" name="today">
|
||||
<div class="tab-body">
|
||||
<div class="date-header">
|
||||
<el-link type="primary" :underline="false" class="nav-link" @click="handlePrevDay">前一天</el-link>
|
||||
<div class="date-title">{{ dateTitle }}</div>
|
||||
<el-link type="primary" :underline="false" class="nav-link" @click="handleNextDay">后一天</el-link>
|
||||
</div>
|
||||
|
||||
<div class="table-card">
|
||||
<el-table :data="todayData" row-key="bh" v-loading="loading" stripe border>
|
||||
<el-table-column type="index" label="序号" width="55" align="center" />
|
||||
<el-table-column label="上课时间" width="130" align="center">
|
||||
<template #default="{ row }">{{ row.sjsj || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="kcmc" label="课程" min-width="140" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="zrdw" label="责任单位" width="110" align="center" />
|
||||
<el-table-column prop="bc" label="班次" width="120" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="skjy" label="教员" width="90" align="center" />
|
||||
<el-table-column label="场地" width="140" align="center" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.jxcd || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="教学内容方法" min-width="160" show-overflow-tooltip header-align="center">
|
||||
<template #default="{ row }">{{ row.jxnrff || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="jybz" label="备注" width="100" show-overflow-tooltip header-align="center">
|
||||
<template #default="{ row }">{{ row.jybz || '-' }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-empty v-show="!loading && !todayData.length" description="暂无教学计划数据" />
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- ==================== 本周教学实施计划 ==================== -->
|
||||
<el-tab-pane label="本周教学实施计划" name="week">
|
||||
<div class="tab-body">
|
||||
<div class="week-header">
|
||||
<el-link type="primary" :underline="false" class="nav-link" @click="handlePrevWeek">上一周</el-link>
|
||||
<div class="week-title">{{ weekRangeText }}</div>
|
||||
<el-link type="primary" :underline="false" class="nav-link" @click="handleNextWeek">下一周</el-link>
|
||||
</div>
|
||||
|
||||
<div class="table-card">
|
||||
<el-table :data="weekData" row-key="bh" v-loading="loading" stripe border>
|
||||
<el-table-column type="index" label="序号" width="55" align="center" />
|
||||
<el-table-column label="上课时间" width="170" align="center" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.sjsj || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="kcmc" label="课程" min-width="130" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="zrdw" label="责任单位" width="100" align="center" />
|
||||
<el-table-column prop="bc" label="班次" width="130" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="skjy" label="教员" width="90" align="center" />
|
||||
<el-table-column label="场地" width="140" align="center" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.jxcd || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="教学内容方法" min-width="150" show-overflow-tooltip header-align="center">
|
||||
<template #default="{ row }">{{ row.jxnrff || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="jybz" label="备注" width="100" show-overflow-tooltip header-align="center">
|
||||
<template #default="{ row }">{{ row.jybz || '-' }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-empty v-show="!loading && !weekData.length" description="本周暂无教学计划数据" />
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- ==================== 教学班次教学实施计划 ==================== -->
|
||||
<el-tab-pane label="教学班次教学实施计划" name="shift">
|
||||
<div class="tab-body">
|
||||
<!-- 选择条件 -->
|
||||
<div class="search-card">
|
||||
<el-form :model="searchForm" inline class="search-form">
|
||||
<el-form-item label="队别班次">
|
||||
<el-select v-model="searchForm.teamClass" placeholder="请选择队别班次" clearable filterable class="shift-select">
|
||||
<el-option v-for="item in teamClassOptions" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 标题 -->
|
||||
<div class="page-title">{{ pageTitle }}</div>
|
||||
|
||||
<!-- 下载操作按钮 -->
|
||||
<el-card shadow="never" class="action-card">
|
||||
<div class="button-row">
|
||||
<el-button type="primary" plain size="mini" @click="handleExportPlan">学期教学实施计划</el-button>
|
||||
<el-button type="primary" plain size="mini" @click="handleExportGrades">学期成绩表</el-button>
|
||||
<el-button type="primary" plain size="mini" @click="handleExportCourses">课程列表另存Excel</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-card">
|
||||
<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 label="课程名称/课时系数" min-width="220" align="center">
|
||||
<template #default="{ row }">
|
||||
<div>{{ row.kcmc || '-' }}</div>
|
||||
<div class="sub-text">{{ row.kssk || '-' }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="zrjs" label="责任教员/课次" min-width="150" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="bc" label="班次" min-width="120" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="nj" label="年级" width="80" align="center" />
|
||||
<el-table-column prop="zy" label="专业" min-width="120" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="jhxs" label="计划学时" width="90" align="center" />
|
||||
<el-table-column prop="yxxs" label="运行学时" width="90" align="center" />
|
||||
<el-table-column prop="khlxfs" label="考核类型方式" min-width="140" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="ssjs" label="实施教员" min-width="120" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="rscd" label="人数/场地" min-width="140" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="kcjd" label="课程进度" width="120" align="center" />
|
||||
<el-table-column prop="ssjhbg" label="实施计划变更" min-width="120" align="center" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<el-empty v-show="!loading && !shiftData.length" description="请选择队别班次后查询" />
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listToday, listWeek, listClass, exportClassPlan, exportClassGrades, exportClassCourses } from '@/api/teachBusiness/timetable'
|
||||
import { listTeam } from '@/api/studentRecords/team'
|
||||
|
||||
const WEEK_DAY_NAMES = ['日', '一', '二', '三', '四', '五', '六']
|
||||
|
||||
function pad2(n) {
|
||||
return n < 10 ? '0' + n : '' + n
|
||||
}
|
||||
|
||||
function formatDate(d) {
|
||||
return d.getFullYear() + '-' + pad2(d.getMonth() + 1) + '-' + pad2(d.getDate())
|
||||
}
|
||||
|
||||
function getMonday(d) {
|
||||
const day = d.getDay() || 7
|
||||
const monday = new Date(d)
|
||||
monday.setDate(d.getDate() - day + 1)
|
||||
return monday
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'Timetable',
|
||||
data() {
|
||||
return {
|
||||
activeTab: 'today',
|
||||
loading: false,
|
||||
// 今日
|
||||
todayDate: new Date(),
|
||||
dayOffset: 0,
|
||||
todayData: [],
|
||||
// 本周
|
||||
weekStart: getMonday(new Date()),
|
||||
weekOffset: 0,
|
||||
weekData: [],
|
||||
// 班次
|
||||
searchForm: { teamClass: '' },
|
||||
teamClassOptions: [],
|
||||
teamMap: {},
|
||||
shiftData: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
selectedTodayDate() {
|
||||
const date = new Date(this.todayDate)
|
||||
date.setDate(date.getDate() + this.dayOffset)
|
||||
return date
|
||||
},
|
||||
selectedWeekStart() {
|
||||
const date = new Date(this.weekStart)
|
||||
date.setDate(date.getDate() + this.weekOffset * 7)
|
||||
return date
|
||||
},
|
||||
dateTitle() {
|
||||
return formatDate(this.selectedTodayDate) + ' 今日教学实施计划'
|
||||
},
|
||||
weekRangeText() {
|
||||
const end = new Date(this.selectedWeekStart)
|
||||
end.setDate(end.getDate() + 6)
|
||||
return formatDate(this.selectedWeekStart) + '(' + this.weekDayName(this.selectedWeekStart) + ') 至 ' +
|
||||
formatDate(end) + '(' + this.weekDayName(end) + ') 本周教学实施计划'
|
||||
},
|
||||
pageTitle() {
|
||||
const name = this.searchForm.teamClass || ''
|
||||
return (name ? name + ' ' : '') + '教学班次教学实施计划'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadTeamOptions()
|
||||
this.getTodayList()
|
||||
this.getWeekList()
|
||||
},
|
||||
methods: {
|
||||
weekDayName(d) {
|
||||
return WEEK_DAY_NAMES[d.getDay()]
|
||||
},
|
||||
/* ---------- 今日:日期导航 ---------- */
|
||||
handlePrevDay() {
|
||||
this.dayOffset -= 1
|
||||
this.getTodayList()
|
||||
},
|
||||
handleNextDay() {
|
||||
this.dayOffset += 1
|
||||
this.getTodayList()
|
||||
},
|
||||
/* ---------- 本周:周次导航 ---------- */
|
||||
handlePrevWeek() {
|
||||
this.weekOffset -= 1
|
||||
this.getWeekList()
|
||||
},
|
||||
handleNextWeek() {
|
||||
this.weekOffset += 1
|
||||
this.getWeekList()
|
||||
},
|
||||
/* ---------- 队别班次下拉(真实接口) ---------- */
|
||||
loadTeamOptions() {
|
||||
listTeam({ pageNum: 1, pageSize: 1000 }).then(response => {
|
||||
const data = response.data || {}
|
||||
const list = data.records || []
|
||||
const map = {}
|
||||
;(list || []).forEach(item => {
|
||||
if (item.xydmc) map[item.xydmc] = item.xydbh
|
||||
})
|
||||
this.teamMap = map
|
||||
this.teamClassOptions = list.map(item => item.xydmc).filter(Boolean)
|
||||
}).catch(() => {
|
||||
this.teamMap = {}
|
||||
this.teamClassOptions = []
|
||||
})
|
||||
},
|
||||
/* ---------- 数据字段映射(接口字段 -> 页面字段) ---------- */
|
||||
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
|
||||
return row
|
||||
},
|
||||
extractLessonRows(response) {
|
||||
const data = response && response.data
|
||||
if (Array.isArray(data)) {
|
||||
return data
|
||||
}
|
||||
if (!data) {
|
||||
return []
|
||||
}
|
||||
|
||||
// 新接口返回 DailyWeeklyTimetableRangeVO,列表位于 data.list;
|
||||
// records 分支用于兼容旧分页结构,避免后端版本切换时页面再次无数据。
|
||||
if (Array.isArray(data.list)) {
|
||||
return data.list
|
||||
}
|
||||
if (Array.isArray(data.records)) {
|
||||
return data.records
|
||||
}
|
||||
|
||||
return []
|
||||
},
|
||||
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() {
|
||||
const params = {
|
||||
offset: this.dayOffset,
|
||||
rq: formatDate(this.todayDate)
|
||||
}
|
||||
this.loading = true
|
||||
listToday(params).then(response => {
|
||||
this.todayData = this.extractLessonRows(response).map(item => this.mapLessonRow(item))
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.todayData = []
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
/* ---------- 本周:拉取数据 ---------- */
|
||||
getWeekList() {
|
||||
const params = {
|
||||
offset: this.weekOffset,
|
||||
rq: formatDate(this.weekStart)
|
||||
}
|
||||
this.loading = true
|
||||
listWeek(params).then(response => {
|
||||
this.weekData = this.extractLessonRows(response).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 || {}
|
||||
this.shiftData = (data.records || []).map(item => this.mapClassRow(item))
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.shiftData = []
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
/* ---------- 班次:查询 ---------- */
|
||||
handleQuery() {
|
||||
if (!this.searchForm.teamClass) {
|
||||
this.$message.warning('请先选择队别班次')
|
||||
return
|
||||
}
|
||||
this.getShiftList()
|
||||
},
|
||||
/* ---------- 下载 ---------- */
|
||||
downloadBlob(blob, filename) {
|
||||
const link = document.createElement('a')
|
||||
link.href = window.URL.createObjectURL(blob)
|
||||
link.download = filename
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
window.URL.revokeObjectURL(link.href)
|
||||
},
|
||||
shiftQueryParams() {
|
||||
if (!this.searchForm.teamClass) return null
|
||||
const xydbh = this.teamMap[this.searchForm.teamClass] || this.searchForm.teamClass
|
||||
return { xydbh: xydbh }
|
||||
},
|
||||
/** 下载学期教学实施计划 Excel(GET /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(() => {})
|
||||
},
|
||||
/** 下载学期成绩表 Excel(GET /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(() => {})
|
||||
},
|
||||
/** 班次课程列表另存 Excel(GET /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(() => {})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.timetable-page {
|
||||
.timetable-tabs {
|
||||
background: #fff;
|
||||
padding: 0 16px;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.tab-body {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.sub-text {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* 日期/周次导航 */
|
||||
.date-header,
|
||||
.week-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 24px;
|
||||
margin-bottom: 12px;
|
||||
padding: 14px 16px;
|
||||
background: #fafafa;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
|
||||
.nav-link {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.date-title,
|
||||
.week-title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
/* 班次 */
|
||||
.search-card {
|
||||
margin-bottom: 12px;
|
||||
|
||||
.search-form {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.shift-select {
|
||||
width: 240px;
|
||||
}
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
color: #303133;
|
||||
text-align: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.action-card {
|
||||
margin-bottom: 12px;
|
||||
|
||||
.button-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,892 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<!-- 统计卡片 -->
|
||||
<div class="section-card">
|
||||
<div class="stat-grid">
|
||||
<div
|
||||
v-for="card in statCards"
|
||||
:key="card.title"
|
||||
class="stat-card"
|
||||
:style="{ background: card.gradient }"
|
||||
tabindex="0"
|
||||
role="button"
|
||||
@click="handleStatClick(card)"
|
||||
@keydown.enter="handleStatClick(card)"
|
||||
>
|
||||
<span class="stat-text">{{ card.title }}</span>
|
||||
<span class="stat-value">{{ card.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 查询条件 -->
|
||||
<div class="section-card">
|
||||
<el-form :model="queryParams" :inline="true" size="small" class="search-form" @submit.native.prevent>
|
||||
<el-form-item label="年度">
|
||||
<el-select v-model="queryParams.nd" placeholder="请选择年度" clearable style="width: 140px">
|
||||
<el-option v-for="y in yearOptions" :key="y" :label="y" :value="y" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="申请教员编号">
|
||||
<el-input v-model="queryParams.sqjybh" placeholder="请输入申请教员编号" clearable style="width: 180px" @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="教研室审批状态">
|
||||
<el-select v-model="queryParams.jyspzzt" placeholder="请选择" clearable style="width: 150px">
|
||||
<el-option v-for="item in auditStatusOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 调课调整申请列表 -->
|
||||
<div class="section-card">
|
||||
<div class="section-header">
|
||||
<div class="section-title">调停补课申请列表</div>
|
||||
<div class="header-actions">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="small" @click="openAdd">新增申请</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-table :data="tableData" v-loading="loading" size="small" border stripe class="compact-table" max-height="520">
|
||||
<el-table-column type="index" label="序号" width="55" align="center" />
|
||||
<el-table-column prop="kcmc" label="课程名称" width="200" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="申请教员" width="150" align="center" show-overflow-tooltip>
|
||||
<template slot-scope="scope">{{ scope.row.sqjyxm || scope.row.sqjybh || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sy" label="调课事由" width="230" show-overflow-tooltip header-align="center" />
|
||||
<el-table-column label="拟调整时间" width="200" align="center" show-overflow-tooltip>
|
||||
<template slot-scope="scope">{{ fmtRqJc(scope.row.rq, scope.row.jc) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="nd" label="年度" width="150" align="center" />
|
||||
<el-table-column label="教研室审批状态" width="150" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="auditStatusTag(scope.row.jyspzzt).type" size="mini">{{ auditStatusTag(scope.row.jyspzzt).label }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="教研室查收状态" width="150" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="receiveStatusTag(scope.row.jyscszt).type" size="mini">{{ receiveStatusTag(scope.row.jyscszt).label }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" width="150" align="center">
|
||||
<template slot-scope="scope">{{ fmtDateTime(scope.row.cjsj) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="180" align="center" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<div class="ops-cell">
|
||||
<el-button type="text" size="mini" icon="el-icon-view" @click="openDetail(scope.row)">详情</el-button>
|
||||
<el-button v-if="showAuditMenu(scope.row)" type="text" size="mini" @click="openAudit(scope.row)">审批</el-button>
|
||||
<el-button v-if="scope.row.sczt === 0 && scope.row.jyspzzt !== 1" type="text" size="mini" class="danger-btn" @click="handleCancel(scope.row)">撤销</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-empty v-show="!loading && tableData.length === 0" description="暂无调整申请" />
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="loadList"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 新增申请弹窗 -->
|
||||
<el-dialog title="新增课表调整申请" :visible.sync="addVisible" width="640px" append-to-body>
|
||||
<el-form ref="addForm" :model="addForm" :rules="addRules" label-width="110px">
|
||||
<el-form-item label="年度" prop="nd">
|
||||
<el-select v-model="addForm.nd" placeholder="请选择年度" style="width: 100%" @change="handleAddYearChange">
|
||||
<el-option v-for="y in yearOptions" :key="y" :label="y" :value="y" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="课次编号" prop="sskcbbh">
|
||||
<el-input v-model="addForm.sskcbbh" placeholder="请从可供调课课次中选择" disabled />
|
||||
<el-button type="primary" plain size="mini" class="pick-lesson-btn" :loading="lessonLoading" @click="loadAdjustableLessons">选择可供调课课次</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="调课事由" prop="sy">
|
||||
<el-input
|
||||
v-model="addForm.sy"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
placeholder="请输入调课事由"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="拟调整日期" prop="rq">
|
||||
<el-date-picker v-model="addForm.rq" type="date" value-format="yyyy-MM-dd" placeholder="请选择日期" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="拟调整节次" prop="jc">
|
||||
<el-select v-model="addForm.jc" placeholder="请选择节次" style="width: 100%">
|
||||
<el-option v-for="n in jcOptions" :key="n" :label="jcLabel(n)" :value="n" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="申请教员">
|
||||
<el-input v-model="addForm.sqjybh" placeholder="由服务端根据当前登录人写入" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="学员队名称">
|
||||
<el-input v-model="addForm.xydmc" placeholder="选择可供调课课次后自动带出" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="原教室编号">
|
||||
<el-input v-model="addForm.yjsbh" placeholder="选择可供调课课次后自动带出" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="拟调整教室编号">
|
||||
<el-select
|
||||
v-model="addForm.xjsbh"
|
||||
placeholder="请选择拟调整教室"
|
||||
clearable
|
||||
filterable
|
||||
:loading="classroomLoading"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="room in classroomOptions"
|
||||
:key="room.jsbh"
|
||||
:label="classroomOptionLabel(room)"
|
||||
:value="room.jsbh"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="原上课时间">
|
||||
<el-input v-model="addForm.ydsjap" placeholder="选择可供调课课次后自动带出" disabled />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" :loading="addLoading" @click="submitAdd">提交申请</el-button>
|
||||
<el-button @click="addVisible = false">取消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 可供调课课次选择弹窗 -->
|
||||
<el-dialog title="选择可供调课课次" :visible.sync="lessonDialogVisible" width="760px" append-to-body>
|
||||
<el-table :data="lessonOptions" v-loading="lessonLoading" size="small" border stripe max-height="420">
|
||||
<el-table-column prop="kcmc" label="课程名称" min-width="140" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="原上课时间" width="160" align="center">
|
||||
<template slot-scope="scope">{{ fmtRqJc(scope.row.rq, scope.row.jc) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="xydmc" label="学员队" min-width="120" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="kcxh" label="课次序号" width="90" align="center" />
|
||||
<el-table-column prop="jsbh" label="教室编号" width="110" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="90" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" @click="pickLesson(scope.row)">选择</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-empty v-show="!lessonLoading && lessonOptions.length === 0" description="暂无可供调课课次" />
|
||||
</el-dialog>
|
||||
|
||||
<!-- 审批弹窗 -->
|
||||
<el-dialog title="教研室审批" :visible.sync="auditVisible" width="520px" append-to-body>
|
||||
<el-form ref="auditForm" :model="auditForm" label-width="100px">
|
||||
<el-form-item label="审批结果" required>
|
||||
<el-radio-group v-model="auditForm.spzt">
|
||||
<el-radio :label="1">同意</el-radio>
|
||||
<el-radio :label="2">发回</el-radio>
|
||||
<el-radio :label="3">拒绝</el-radio>
|
||||
</el-radio-group>
|
||||
<div class="form-tip">点审批即已查收</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="审批意见">
|
||||
<el-input v-model="auditForm.fhyj" type="textarea" :rows="3" placeholder="请输入审批意见(发回/拒绝时必填)" />
|
||||
</el-form-item>
|
||||
<el-form-item label="审批人编号">
|
||||
<el-input v-model="auditForm.sprbh" placeholder="不填默认取当前登录人" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" :loading="auditLoading" @click="submitAudit">确定</el-button>
|
||||
<el-button @click="auditVisible = false">取消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 查看详情弹窗 -->
|
||||
<el-dialog title="申请详情" :visible.sync="detailVisible" width="760px" append-to-body>
|
||||
<div v-loading="detailLoading">
|
||||
<el-descriptions v-if="detailData" :column="2" border size="small">
|
||||
<el-descriptions-item label="课程名称">{{ detailData.kcmc || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="申请教员">{{ detailData.sqjyxm || detailData.sqjybh || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="调课事由" :span="2">{{ detailData.sy || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="原上课时间">{{ detailData.ydsjap || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="拟调整时间">{{ fmtRqJc(detailData.rq, detailData.jc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="年度">{{ detailData.nd || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">{{ fmtDateTime(detailData.cjsj) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="教研室审批状态">
|
||||
<el-tag :type="auditStatusTag(detailData.jyspzzt).type" size="mini">{{ auditStatusTag(detailData.jyspzzt).label }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="教研室查收状态">
|
||||
<el-tag :type="receiveStatusTag(detailData.jyscszt).type" size="mini">{{ receiveStatusTag(detailData.jyscszt).label }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="教研室审批人">{{ detailData.jyspzrbh || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="教研室审批时间">{{ fmtDateTime(detailData.jyspzsj) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="教研室查收人">{{ detailData.jyscsrbh || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="教研室查收时间">{{ fmtDateTime(detailData.jyscssj) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="教学内容" :span="2">{{ detailData.jxnr || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="教学要点" :span="2">{{ detailData.jxyd || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="教学方法" :span="2">{{ detailData.jxff || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="教学保障备注" :span="2">{{ detailData.jxbzbz || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="用车信息" :span="2">{{ detailData.ycxx || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="2">{{ detailData.bz || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 新教室 -->
|
||||
<div v-if="detailData && detailData.roomList && detailData.roomList.length" class="sub-section">
|
||||
<div class="sub-title">新教室</div>
|
||||
<el-table :data="detailData.roomList" size="small" border stripe>
|
||||
<el-table-column prop="jsbh" label="教室编号" min-width="120" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="jsmc" label="教室名称" min-width="140" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="bz" label="备注" min-width="160" show-overflow-tooltip header-align="center" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 新辅助教员 -->
|
||||
<div v-if="detailData && detailData.teacherList && detailData.teacherList.length" class="sub-section">
|
||||
<div class="sub-title">新辅助教员</div>
|
||||
<el-table :data="detailData.teacherList" size="small" border stripe>
|
||||
<el-table-column prop="fzjybh" label="教员编号" min-width="120" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="fzjyxm" label="教员姓名" min-width="120" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="是否主教员" width="100" align="center">
|
||||
<template slot-scope="scope">{{ scope.row.zjy === 1 ? '是' : '否' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="bz" label="备注" min-width="140" show-overflow-tooltip header-align="center" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 新学员队 -->
|
||||
<div v-if="detailData && detailData.teamList && detailData.teamList.length" class="sub-section">
|
||||
<div class="sub-title">新学员队</div>
|
||||
<el-table :data="detailData.teamList" size="small" border stripe>
|
||||
<el-table-column prop="xydbh" label="学员队编号" min-width="140" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="xydmc" label="学员队名称" min-width="140" align="center" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 新保障明细 -->
|
||||
<div v-if="detailData && detailData.supportList && detailData.supportList.length" class="sub-section">
|
||||
<div class="sub-title">新保障明细</div>
|
||||
<el-table :data="detailData.supportList" size="small" border stripe>
|
||||
<el-table-column prop="bztgmxbh" label="保障编号" min-width="140" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="bztgmxmc" label="保障名称" min-width="160" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="sl" label="数量" width="80" align="center" />
|
||||
<el-table-column prop="bz" label="备注" min-width="140" show-overflow-tooltip header-align="center" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 机关审批记录 -->
|
||||
<div v-if="detailData && detailData.auditList && detailData.auditList.length" class="sub-section">
|
||||
<div class="sub-title">机关审批记录</div>
|
||||
<el-table :data="detailData.auditList" size="small" border stripe>
|
||||
<el-table-column prop="jgmc" label="机关" min-width="140" align="center" show-overflow-tooltip>
|
||||
<template slot-scope="scope">{{ scope.row.jgmc || scope.row.jgbh || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审批状态" width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="auditStatusTag(scope.row.spzt).type" size="mini">{{ auditStatusTag(scope.row.spzt).label }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sprxm" label="审批人" min-width="110" align="center" show-overflow-tooltip>
|
||||
<template slot-scope="scope">{{ scope.row.sprxm || scope.row.sprbh || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审批时间" width="150" align="center">
|
||||
<template slot-scope="scope">{{ fmtDateTime(scope.row.spsj) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="fhyj" label="发回意见" min-width="140" show-overflow-tooltip header-align="center" />
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="detailVisible = false">关闭</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
listScheduleAdjust,
|
||||
listAdjustableLessons,
|
||||
getScheduleAdjustDetail,
|
||||
submitScheduleAdjust,
|
||||
auditByTeachingOffice,
|
||||
cancelScheduleAdjust
|
||||
} from '@/api/teachBusiness/courseRunning'
|
||||
import { listAllSemester } from '@/api/teachBusiness/semester'
|
||||
import { listAllClassroom } from '@/api/teachBusiness/classroom'
|
||||
|
||||
// 节次 -> 节次区间映射
|
||||
const JC_SECTION = {
|
||||
1: '1-2节', 2: '3-4节', 3: '5-6节', 4: '7-8节', 5: '9-10节', 6: '11-12节'
|
||||
}
|
||||
|
||||
// 审批状态:0-未审批,1-已同意,2-已发回,3-已拒绝
|
||||
const AUDIT_STATUS = {
|
||||
0: { label: '未审批', type: 'info' },
|
||||
1: { label: '已同意', type: 'success' },
|
||||
2: { label: '已发回', type: 'warning' },
|
||||
3: { label: '已拒绝', type: 'danger' }
|
||||
}
|
||||
|
||||
// 查收状态:0-未查收,1-已查收
|
||||
const RECEIVE_STATUS = {
|
||||
0: { label: '未查收', type: 'info' },
|
||||
1: { label: '已查收', type: 'success' }
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'TimetableAdjust',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
tableData: [],
|
||||
total: 0,
|
||||
queryParams: {
|
||||
nd: undefined,
|
||||
sqjybh: undefined,
|
||||
jyspzzt: undefined,
|
||||
pageNum: 1,
|
||||
pageSize: 20
|
||||
},
|
||||
// 年度下拉数据来自 /semester/all(真实后端数据)
|
||||
yearOptions: [],
|
||||
defaultNd: undefined,
|
||||
jcOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
|
||||
auditStatusOptions: [
|
||||
{ label: '未审批', value: 0 },
|
||||
{ label: '已同意', value: 1 },
|
||||
{ label: '已发回', value: 2 },
|
||||
{ label: '已拒绝', value: 3 }
|
||||
],
|
||||
statCards: [],
|
||||
// 新增申请
|
||||
addVisible: false,
|
||||
addLoading: false,
|
||||
addForm: {},
|
||||
addRules: {
|
||||
nd: [{ required: true, message: '请选择年度', trigger: 'change' }],
|
||||
sskcbbh: [{ required: true, message: '请选择可供调课课次', trigger: 'change' }],
|
||||
sy: [{ required: true, message: '请输入调课事由', trigger: 'blur' }],
|
||||
rq: [{ required: true, message: '请选择拟调整日期', trigger: 'change' }],
|
||||
jc: [{ required: true, message: '请选择拟调整节次', trigger: 'change' }]
|
||||
},
|
||||
// 可供调课课次
|
||||
lessonDialogVisible: false,
|
||||
lessonLoading: false,
|
||||
lessonOptions: [],
|
||||
classroomLoading: false,
|
||||
classroomOptions: [],
|
||||
// 审批
|
||||
auditVisible: false,
|
||||
auditLoading: false,
|
||||
auditForm: { ssdksqbh: '', spzt: 1, fhyj: '', sprbh: '' },
|
||||
// 详情
|
||||
detailVisible: false,
|
||||
detailLoading: false,
|
||||
detailData: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadYearOptions().then(() => this.loadList())
|
||||
},
|
||||
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.queryParams.nd) this.queryParams.nd = this.defaultNd
|
||||
return arr
|
||||
}).catch(() => {
|
||||
this.yearOptions = []
|
||||
this.defaultNd = undefined
|
||||
return []
|
||||
})
|
||||
},
|
||||
/* ---------- 通用格式化 ---------- */
|
||||
fmtDateTime(v) {
|
||||
if (!v) return '-'
|
||||
return String(v).replace('T', ' ').substring(0, 16)
|
||||
},
|
||||
fmtRqJc(rq, jc) {
|
||||
if (!rq) return '-'
|
||||
const date = String(rq).substring(0, 10)
|
||||
const sec = jc === null || jc === undefined || jc === '' ? '第?节' : (JC_SECTION[jc] || '第' + jc + '节')
|
||||
return date + ' ' + sec
|
||||
},
|
||||
jcLabel(n) {
|
||||
return JC_SECTION[n] || ('第' + n + '节')
|
||||
},
|
||||
auditStatusTag(v) {
|
||||
return AUDIT_STATUS[v] || { label: '-', type: 'info' }
|
||||
},
|
||||
receiveStatusTag(v) {
|
||||
return RECEIVE_STATUS[v] || { label: '-', type: 'info' }
|
||||
},
|
||||
/* ---------- 列表查询 ---------- */
|
||||
loadList() {
|
||||
const params = {
|
||||
pageNum: this.queryParams.pageNum,
|
||||
pageSize: this.queryParams.pageSize
|
||||
}
|
||||
if (this.queryParams.nd) params.nd = this.queryParams.nd
|
||||
if (this.queryParams.sqjybh) params.sqjybh = this.queryParams.sqjybh
|
||||
if (this.queryParams.jyspzzt !== undefined && this.queryParams.jyspzzt !== '') {
|
||||
params.jyspzzt = this.queryParams.jyspzzt
|
||||
}
|
||||
this.loading = true
|
||||
listScheduleAdjust(params).then(response => {
|
||||
const data = response.data || {}
|
||||
this.tableData = data.records || []
|
||||
this.total = data.total || 0
|
||||
this.refreshStatCards()
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.tableData = []
|
||||
this.total = 0
|
||||
this.refreshStatCards()
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.loadList()
|
||||
},
|
||||
resetQuery() {
|
||||
this.queryParams = {
|
||||
nd: this.defaultNd,
|
||||
sqjybh: undefined,
|
||||
jyspzzt: undefined,
|
||||
pageNum: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
this.loadList()
|
||||
},
|
||||
refreshStatCards() {
|
||||
const list = this.tableData
|
||||
this.statCards = [
|
||||
{ title: '本页申请', value: list.length, gradient: 'linear-gradient(135deg, #00875a 0%, #00b877 100%)', filter: undefined },
|
||||
{ title: '教研室待审批', value: list.filter(i => i.jyspzzt === 0).length, gradient: 'linear-gradient(135deg, #e6a23c 0%, #f8b04c 100%)', filter: 0 },
|
||||
{ title: '教研室已同意', value: list.filter(i => i.jyspzzt === 1).length, gradient: 'linear-gradient(135deg, #409eff 0%, #66b1ff 100%)', filter: 1 },
|
||||
{ title: '教研室已拒绝', value: list.filter(i => i.jyspzzt === 3).length, gradient: 'linear-gradient(135deg, #f56c6c 0%, #f78989 100%)', filter: 3 }
|
||||
]
|
||||
},
|
||||
handleStatClick(card) {
|
||||
if (card.filter === undefined) return
|
||||
this.queryParams.jyspzzt = this.queryParams.jyspzzt === card.filter ? undefined : card.filter
|
||||
this.handleQuery()
|
||||
},
|
||||
/* ---------- 新增申请 ---------- */
|
||||
openAdd() {
|
||||
this.addForm = {
|
||||
nd: this.defaultNd || this.yearOptions[0],
|
||||
sskcbbh: '',
|
||||
sy: '',
|
||||
rq: '',
|
||||
jc: 1,
|
||||
sqjybh: '',
|
||||
xydrwbh: '',
|
||||
kbh: '',
|
||||
kcbbh: '',
|
||||
xydmc: '',
|
||||
yjsbh: '',
|
||||
xjsbh: '',
|
||||
ydsjap: '',
|
||||
jxnr: '',
|
||||
jxyd: '',
|
||||
jxff: '',
|
||||
jxbzbz: '',
|
||||
ycxx: '',
|
||||
bz: '',
|
||||
roomList: [],
|
||||
teacherList: [],
|
||||
teamList: [],
|
||||
supportList: []
|
||||
}
|
||||
this.lessonOptions = []
|
||||
this.loadClassroomOptions()
|
||||
this.$nextTick(() => this.$refs.addForm && this.$refs.addForm.clearValidate())
|
||||
this.addVisible = true
|
||||
},
|
||||
handleAddYearChange() {
|
||||
Object.assign(this.addForm, {
|
||||
sskcbbh: '',
|
||||
rq: '',
|
||||
jc: 1,
|
||||
sqjybh: '',
|
||||
xydrwbh: '',
|
||||
kbh: '',
|
||||
kcbbh: '',
|
||||
xydmc: '',
|
||||
yjsbh: '',
|
||||
xjsbh: '',
|
||||
ydsjap: '',
|
||||
jxnr: '',
|
||||
jxyd: '',
|
||||
jxff: '',
|
||||
jxbzbz: '',
|
||||
ycxx: '',
|
||||
bz: '',
|
||||
roomList: [],
|
||||
teacherList: [],
|
||||
teamList: [],
|
||||
supportList: []
|
||||
})
|
||||
this.lessonOptions = []
|
||||
},
|
||||
loadClassroomOptions() {
|
||||
this.classroomLoading = true
|
||||
return listAllClassroom().then(response => {
|
||||
const classrooms = Array.isArray(response.data) ? response.data : []
|
||||
this.classroomOptions = classrooms
|
||||
.filter(room => room.jsbh && !this.isDisabledValue(room.ty))
|
||||
.sort((first, second) => String(first.jsbh).localeCompare(String(second.jsbh), 'zh-CN'))
|
||||
}).catch(() => {
|
||||
this.classroomOptions = []
|
||||
this.$message.warning('教室列表加载失败,请稍后重试')
|
||||
}).finally(() => {
|
||||
this.classroomLoading = false
|
||||
})
|
||||
},
|
||||
classroomOptionLabel(room) {
|
||||
return room.jsmc ? room.jsbh + ' · ' + room.jsmc : room.jsbh
|
||||
},
|
||||
isDisabledValue(value) {
|
||||
return value === true || value === 1 || value === '1' || value === 'true'
|
||||
},
|
||||
loadAdjustableLessons() {
|
||||
if (!this.addForm.nd) {
|
||||
this.$message.warning('请先选择年度')
|
||||
return
|
||||
}
|
||||
this.lessonLoading = true
|
||||
listAdjustableLessons({ nd: this.addForm.nd }).then(response => {
|
||||
const data = response.data || []
|
||||
this.lessonOptions = Array.isArray(data) ? data : (data.records || [])
|
||||
this.lessonLoading = false
|
||||
this.lessonDialogVisible = true
|
||||
}).catch(() => {
|
||||
this.lessonLoading = false
|
||||
this.$message.warning('加载可供调课课次失败,请稍后重试')
|
||||
})
|
||||
},
|
||||
pickLesson(row) {
|
||||
const lessonNumber = row.sskcbbh || row.bh || ''
|
||||
if (!lessonNumber) {
|
||||
this.$message.warning('当前课次缺少课次编号,无法选择')
|
||||
return
|
||||
}
|
||||
const currentRoomNumber = row.jsbh || row.yjsbh || row.xjsbh || ''
|
||||
const roomList = this.normalizeRoomList(row.roomList, currentRoomNumber)
|
||||
const teamList = this.normalizeTeamList(row.teamList, row.xydbh)
|
||||
Object.assign(this.addForm, {
|
||||
sskcbbh: lessonNumber,
|
||||
rq: row.rq ? String(row.rq).substring(0, 10) : '',
|
||||
jc: row.jc === null || row.jc === undefined ? 1 : Number(row.jc),
|
||||
nd: row.nd || this.addForm.nd,
|
||||
sqjybh: row.sqjybh || '',
|
||||
xydrwbh: row.xydrwbh || '',
|
||||
kbh: row.kbh || '',
|
||||
kcbbh: row.kcbbh || '',
|
||||
xydmc: row.xydmc || '',
|
||||
yjsbh: row.yjsbh || currentRoomNumber,
|
||||
xjsbh: row.xjsbh || currentRoomNumber,
|
||||
ydsjap: row.rq ? this.fmtRqJc(row.rq, row.jc) : (row.ydsjap || ''),
|
||||
jxnr: row.jxnr || '',
|
||||
jxyd: row.jxyd || '',
|
||||
jxff: row.jxff || '',
|
||||
jxbzbz: row.jxbzbz || '',
|
||||
ycxx: row.ycxx || '',
|
||||
bz: row.bz || '',
|
||||
roomList: roomList,
|
||||
teacherList: this.normalizeTeacherList(row.teacherList),
|
||||
teamList: teamList,
|
||||
supportList: this.normalizeSupportList(row.supportList)
|
||||
})
|
||||
;['jysdh', 'kcmc', 'sqjyxm'].forEach(key => {
|
||||
if (row[key] !== undefined && row[key] !== null) this.addForm[key] = row[key]
|
||||
})
|
||||
this.lessonDialogVisible = false
|
||||
this.$nextTick(() => this.$refs.addForm && this.$refs.addForm.validateField('sskcbbh'))
|
||||
this.$message.success('已选择课次:' + (row.kcmc || lessonNumber))
|
||||
},
|
||||
submitAdd() {
|
||||
this.$refs.addForm.validate(valid => {
|
||||
if (!valid) return
|
||||
const payload = {
|
||||
sskcbbh: this.addForm.sskcbbh,
|
||||
sy: this.addForm.sy,
|
||||
rq: this.addForm.rq + 'T00:00:00',
|
||||
jc: this.addForm.jc,
|
||||
nd: this.addForm.nd,
|
||||
roomList: this.buildSubmitRoomList(),
|
||||
teacherList: this.normalizeTeacherList(this.addForm.teacherList),
|
||||
teamList: this.normalizeTeamList(this.addForm.teamList),
|
||||
supportList: this.normalizeSupportList(this.addForm.supportList)
|
||||
}
|
||||
const optionalFields = [
|
||||
'sqjybh', 'xydrwbh', 'kbh', 'kcbbh', 'xjsbh', 'jxnr', 'jxyd',
|
||||
'jxff', 'jxbzbz', 'ycxx', 'bz'
|
||||
]
|
||||
optionalFields.forEach(key => {
|
||||
if (this.addForm[key]) payload[key] = this.addForm[key]
|
||||
})
|
||||
this.addLoading = true
|
||||
submitScheduleAdjust(payload).then(() => {
|
||||
this.addLoading = false
|
||||
this.addVisible = false
|
||||
this.$message.success('申请提交成功')
|
||||
this.loadList()
|
||||
}).catch(() => {
|
||||
this.addLoading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
normalizeRoomList(roomList, fallbackRoomNumber) {
|
||||
const normalizedList = (Array.isArray(roomList) ? roomList : [])
|
||||
.filter(item => item && item.jsbh)
|
||||
.map(item => ({
|
||||
jsbh: item.jsbh,
|
||||
bz: item.bz || ''
|
||||
}))
|
||||
if (normalizedList.length === 0 && fallbackRoomNumber) {
|
||||
normalizedList.push({ jsbh: fallbackRoomNumber, bz: '' })
|
||||
}
|
||||
return normalizedList
|
||||
},
|
||||
normalizeTeacherList(teacherList) {
|
||||
return (Array.isArray(teacherList) ? teacherList : [])
|
||||
.filter(item => item && item.fzjybh)
|
||||
.map(item => ({ fzjybh: item.fzjybh }))
|
||||
},
|
||||
normalizeTeamList(teamList, fallbackTeamNumber) {
|
||||
const normalizedList = (Array.isArray(teamList) ? teamList : [])
|
||||
.filter(item => item && item.xydbh)
|
||||
.map(item => ({ xydbh: item.xydbh }))
|
||||
if (normalizedList.length === 0 && fallbackTeamNumber) {
|
||||
normalizedList.push({ xydbh: fallbackTeamNumber })
|
||||
}
|
||||
return normalizedList
|
||||
},
|
||||
normalizeSupportList(supportList) {
|
||||
return (Array.isArray(supportList) ? supportList : [])
|
||||
.filter(item => item && item.bztgmxbh)
|
||||
.map(item => ({
|
||||
bztgmxbh: item.bztgmxbh,
|
||||
sl: item.sl === null || item.sl === undefined ? undefined : Number(item.sl)
|
||||
}))
|
||||
},
|
||||
buildSubmitRoomList() {
|
||||
if (!this.addForm.xjsbh) return []
|
||||
const currentRoomList = this.normalizeRoomList(this.addForm.roomList)
|
||||
if (this.addForm.xjsbh === this.addForm.yjsbh && currentRoomList.length > 0) {
|
||||
return currentRoomList
|
||||
}
|
||||
const currentRoom = currentRoomList.find(item => item.jsbh === this.addForm.xjsbh)
|
||||
return [{
|
||||
jsbh: this.addForm.xjsbh,
|
||||
bz: currentRoom ? currentRoom.bz : ''
|
||||
}]
|
||||
},
|
||||
/* ---------- 审批 ---------- */
|
||||
showAuditMenu(row) {
|
||||
return row.sczt === 0 && (row.jyspzzt === 0 || row.jyspzzt === 2 || row.jyspzzt === 3)
|
||||
},
|
||||
openAudit(row) {
|
||||
this.auditForm = {
|
||||
ssdksqbh: row.ssdksqbh,
|
||||
spzt: 1,
|
||||
fhyj: '',
|
||||
sprbh: ''
|
||||
}
|
||||
this.auditVisible = true
|
||||
},
|
||||
submitAudit() {
|
||||
const f = this.auditForm
|
||||
if (f.spzt !== 1 && !f.fhyj) {
|
||||
this.$message.warning('发回/拒绝时请填写审批意见')
|
||||
return
|
||||
}
|
||||
const payload = {
|
||||
ssdksqbh: f.ssdksqbh,
|
||||
spzt: f.spzt,
|
||||
fhyj: f.fhyj
|
||||
}
|
||||
if (f.sprbh) payload.sprbh = f.sprbh
|
||||
this.auditLoading = true
|
||||
auditByTeachingOffice(payload).then(() => {
|
||||
this.auditLoading = false
|
||||
this.auditVisible = false
|
||||
this.$message.success('审批成功')
|
||||
this.loadList()
|
||||
}).catch(() => {
|
||||
this.auditLoading = false
|
||||
})
|
||||
},
|
||||
/* ---------- 撤销 ---------- */
|
||||
handleCancel(row) {
|
||||
this.$confirm('确认撤销该调课申请?', '提示', { type: 'warning' })
|
||||
.then(() => {
|
||||
cancelScheduleAdjust({ ssdksqbh: row.ssdksqbh }).then(() => {
|
||||
this.$message.success('撤销成功')
|
||||
this.loadList()
|
||||
}).catch(() => {})
|
||||
})
|
||||
.catch(() => {})
|
||||
},
|
||||
/* ---------- 详情 ---------- */
|
||||
openDetail(row) {
|
||||
this.detailVisible = true
|
||||
this.detailLoading = true
|
||||
this.detailData = null
|
||||
getScheduleAdjustDetail(row.ssdksqbh).then(response => {
|
||||
this.detailData = response.data || {}
|
||||
this.detailLoading = false
|
||||
}).catch(() => {
|
||||
this.detailData = null
|
||||
this.detailLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.page-container {
|
||||
padding: 16px;
|
||||
|
||||
.section-card {
|
||||
background: #fff;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 6px;
|
||||
padding: 16px 20px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 统计卡片 */
|
||||
.stat-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 16px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 16px 20px;
|
||||
border-radius: 6px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.stat-text {
|
||||
font-size: 13px;
|
||||
opacity: 0.92;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
margin-top: 8px;
|
||||
font-size: 26px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 查询区域 */
|
||||
.search-form {
|
||||
margin-bottom: -16px;
|
||||
|
||||
::v-deep .el-form-item {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.compact-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.danger-btn {
|
||||
color: #f56c6c;
|
||||
|
||||
&:hover {
|
||||
color: #f78989;
|
||||
}
|
||||
}
|
||||
|
||||
.ops-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 0 4px;
|
||||
}
|
||||
|
||||
.form-tip {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
line-height: 1.4;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.pick-lesson-btn {
|
||||
margin-top: 6px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sub-section {
|
||||
margin-top: 16px;
|
||||
|
||||
.sub-title {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #303133;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.page-container .stat-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,484 @@
|
||||
<template>
|
||||
<div class="app-container venue-page">
|
||||
<!-- 查询条件 -->
|
||||
<el-card shadow="never" class="search-card">
|
||||
<el-form :model="searchForm" label-width="100px" class="search-form" @submit.native.prevent>
|
||||
<el-row :gutter="24">
|
||||
<el-col :xs="24" :md="8">
|
||||
<el-form-item label="教室编号">
|
||||
<el-input v-model="searchForm.jsbh" placeholder="请输入教室编号" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="8">
|
||||
<el-form-item label="教室名称">
|
||||
<el-input v-model="searchForm.jsmc" placeholder="请输入教室名称" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="8">
|
||||
<el-form-item label="教学楼代号">
|
||||
<el-input v-model="searchForm.jxldh" placeholder="请输入教学楼代号" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="8">
|
||||
<el-form-item label="教学场地类型">
|
||||
<el-select v-model="searchForm.jxcdlx" placeholder="请选择场地类型" clearable filterable allow-create
|
||||
default-first-option class="w-full">
|
||||
<el-option v-for="item in jxcdlxOptions" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="8">
|
||||
<el-form-item label="停用">
|
||||
<el-radio-group v-model="searchForm.ty">
|
||||
<el-radio :label="false">否</el-radio>
|
||||
<el-radio :label="true">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="8">
|
||||
<div class="search-actions">
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 数据列表 -->
|
||||
<el-card shadow="never" class="table-card">
|
||||
<div class="list-header">
|
||||
<div class="list-title">教室列表</div>
|
||||
<div class="list-actions">
|
||||
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table v-loading="loading" :data="tableData" border stripe highlight-current-row>
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="jsbh" label="教室编号" width="130" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="jsmc" label="教室名称" width="140" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="jxldh" label="教学楼代号" width="150" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="jxcdlx" label="教学场地类型" width="150" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="jc" label="简称" width="100" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="rnrs" label="容纳人数" width="90" align="center" />
|
||||
<el-table-column prop="mj" label="面积" width="90" align="center" />
|
||||
<el-table-column prop="ksrnrs" label="考试容纳人数" width="110" align="center" />
|
||||
<el-table-column prop="ewyxkbs" label="额外可开班数" width="100" align="center" />
|
||||
<el-table-column label="虚实类型" width="90" align="center">
|
||||
<template slot-scope="scope">{{ fmtXslx(scope.row.xslx) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="停用" width="80" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="isTrue(scope.row.ty) ? 'danger' : 'success'" size="mini">
|
||||
{{ isTrue(scope.row.ty) ? '停用' : '正常' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sssb" label="设施设备" width="140" show-overflow-tooltip header-align="center" />
|
||||
<el-table-column label="操作" align="center" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" icon="el-icon-delete" class="danger-text-btn" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
background
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:current-page="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 新增/编辑弹窗 -->
|
||||
<el-dialog :title="dialog.title" :visible.sync="dialog.visible" width="780px" append-to-body
|
||||
:close-on-click-modal="false">
|
||||
<el-form ref="classroomForm" :model="dialog.form" :rules="rules" label-width="110px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="教室名称" prop="jsmc">
|
||||
<el-input v-model="dialog.form.jsmc" placeholder="请输入教室名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="教学楼代号">
|
||||
<el-input v-model="dialog.form.jxldh" placeholder="请输入教学楼代号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="教学场地类型">
|
||||
<el-select v-model="dialog.form.jxcdlx" placeholder="请选择场地类型" clearable filterable allow-create
|
||||
default-first-option class="w-full">
|
||||
<el-option v-for="item in jxcdlxOptions" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="简称">
|
||||
<el-input v-model="dialog.form.jc" placeholder="请输入简称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="容纳人数">
|
||||
<el-input-number v-model="dialog.form.rnrs" :min="0" controls-position="right" class="w-full" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="面积">
|
||||
<div class="number-unit-field">
|
||||
<el-input-number
|
||||
v-model="dialog.form.mj"
|
||||
:min="0"
|
||||
:precision="1"
|
||||
controls-position="right"
|
||||
/>
|
||||
<span class="number-unit">㎡</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="考试容纳人数">
|
||||
<el-input-number v-model="dialog.form.ksrnrs" :min="0" controls-position="right" class="w-full" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="额外可开班数">
|
||||
<el-input-number v-model="dialog.form.ewyxkbs" :min="0" controls-position="right" class="w-full" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="拼音">
|
||||
<el-input v-model="dialog.form.py" placeholder="请输入拼音" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="虚实类型">
|
||||
<el-radio-group v-model="dialog.form.xslx">
|
||||
<el-radio :label="true">实教</el-radio>
|
||||
<el-radio :label="false">非实教</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="停用">
|
||||
<el-radio-group v-model="dialog.form.ty">
|
||||
<el-radio :label="false">正常</el-radio>
|
||||
<el-radio :label="true">停用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设施设备">
|
||||
<el-input v-model="dialog.form.sssb" placeholder="请输入设施设备" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="dialog.form.bz" type="textarea" :rows="2" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialog.visible = false">取 消</el-button>
|
||||
<el-button type="primary" :loading="dialog.submitting" @click="submitDialog">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
addClassroom,
|
||||
deleteClassroom,
|
||||
updateClassroom,
|
||||
listClassroom,
|
||||
listAllClassroom
|
||||
} from '@/api/teachBusiness/classroom'
|
||||
|
||||
export default {
|
||||
name: 'Venue',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
searchForm: {
|
||||
jsbh: '',
|
||||
jsmc: '',
|
||||
jxldh: '',
|
||||
jxcdlx: '',
|
||||
ty: false
|
||||
},
|
||||
tableData: [],
|
||||
jxcdlxOptions: [],
|
||||
total: 0,
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
dialog: {
|
||||
visible: false,
|
||||
title: '',
|
||||
submitting: false,
|
||||
form: this.createEmptyForm()
|
||||
},
|
||||
rules: {
|
||||
jsmc: [{ required: true, message: '请输入教室名称', trigger: 'blur' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadVenueTypeOptions()
|
||||
this.fetchList()
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 独立加载全部场地类型,避免查询结果收窄后下拉候选项同步丢失。
|
||||
*/
|
||||
loadVenueTypeOptions() {
|
||||
return listAllClassroom().then(response => {
|
||||
this.jxcdlxOptions = this.collectVenueTypes(response.data || [])
|
||||
}).catch(() => {
|
||||
// 全量接口异常时保留已收集选项,避免影响列表的基本查询功能。
|
||||
this.mergeVenueTypeOptions(this.tableData)
|
||||
})
|
||||
},
|
||||
|
||||
collectVenueTypes(classrooms) {
|
||||
const venueTypes = new Set()
|
||||
classrooms.forEach(classroom => {
|
||||
const venueType = classroom.jxcdlx && String(classroom.jxcdlx).trim()
|
||||
if (venueType) {
|
||||
venueTypes.add(venueType)
|
||||
}
|
||||
})
|
||||
|
||||
return Array.from(venueTypes).sort((first, second) => first.localeCompare(second, 'zh-CN'))
|
||||
},
|
||||
|
||||
mergeVenueTypeOptions(classrooms) {
|
||||
const venueTypes = new Set(this.jxcdlxOptions)
|
||||
this.collectVenueTypes(classrooms).forEach(venueType => venueTypes.add(venueType))
|
||||
this.jxcdlxOptions = Array.from(venueTypes)
|
||||
.sort((first, second) => first.localeCompare(second, 'zh-CN'))
|
||||
},
|
||||
|
||||
/* ---------- 列表加载 ---------- */
|
||||
fetchList() {
|
||||
this.loading = true
|
||||
const params = {
|
||||
pageNum: this.pageNum,
|
||||
pageSize: this.pageSize
|
||||
}
|
||||
Object.keys(this.searchForm).forEach(key => {
|
||||
const value = this.searchForm[key]
|
||||
if (value !== '' && value !== null && value !== undefined) {
|
||||
params[key] = value
|
||||
}
|
||||
})
|
||||
listClassroom(params).then(response => {
|
||||
const data = response.data || {}
|
||||
this.tableData = data.records || []
|
||||
this.mergeVenueTypeOptions(this.tableData)
|
||||
this.total = data.total || 0
|
||||
}).catch(() => {
|
||||
this.tableData = []
|
||||
this.total = 0
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
/* ---------- 查询 / 重置 ---------- */
|
||||
handleQuery() {
|
||||
this.pageNum = 1
|
||||
this.fetchList()
|
||||
},
|
||||
handleReset() {
|
||||
this.searchForm = {
|
||||
jsbh: '',
|
||||
jsmc: '',
|
||||
jxldh: '',
|
||||
jxcdlx: '',
|
||||
ty: false
|
||||
}
|
||||
this.pageNum = 1
|
||||
this.fetchList()
|
||||
},
|
||||
|
||||
/* ---------- 分页 ---------- */
|
||||
handleSizeChange(size) {
|
||||
this.pageSize = size
|
||||
this.pageNum = 1
|
||||
this.fetchList()
|
||||
},
|
||||
handlePageChange(page) {
|
||||
this.pageNum = page
|
||||
this.fetchList()
|
||||
},
|
||||
|
||||
/* ---------- 新增 / 编辑 ---------- */
|
||||
handleAdd() {
|
||||
this.dialog.title = '新增教学场地'
|
||||
this.dialog.form = this.createEmptyForm()
|
||||
this.dialog.visible = true
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.classroomForm) this.$refs.classroomForm.clearValidate()
|
||||
})
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.dialog.title = '编辑教学场地'
|
||||
this.dialog.form = Object.assign({}, this.createEmptyForm(), row)
|
||||
this.dialog.visible = true
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.classroomForm) this.$refs.classroomForm.clearValidate()
|
||||
})
|
||||
},
|
||||
submitDialog() {
|
||||
this.$refs.classroomForm.validate(valid => {
|
||||
if (!valid) return
|
||||
this.dialog.submitting = true
|
||||
const payload = this.cleanPayload(this.dialog.form)
|
||||
const isEdit = !!payload.id
|
||||
const req = isEdit ? updateClassroom(payload) : addClassroom(payload)
|
||||
req.then(() => {
|
||||
this.$message.success(isEdit ? '修改成功' : '新增成功')
|
||||
this.dialog.visible = false
|
||||
this.loadVenueTypeOptions()
|
||||
this.fetchList()
|
||||
}).catch(() => {}).finally(() => {
|
||||
this.dialog.submitting = false
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
/* ---------- 删除(后端仅提供单条删除,参数为 id) ---------- */
|
||||
handleDelete(row) {
|
||||
this.$confirm('确定删除教室「' + (row.jsmc || row.jsbh) + '」吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
return deleteClassroom(row.id)
|
||||
}).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.loadVenueTypeOptions()
|
||||
this.fetchList()
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
/* ---------- 工具 ---------- */
|
||||
createEmptyForm() {
|
||||
return {
|
||||
id: '',
|
||||
jsbh: '',
|
||||
jsmc: '',
|
||||
jxldh: '',
|
||||
jxcdlx: '',
|
||||
jc: '',
|
||||
rnrs: null,
|
||||
mj: null,
|
||||
ksrnrs: null,
|
||||
ewyxkbs: null,
|
||||
xh: '',
|
||||
py: '',
|
||||
xslx: false,
|
||||
ty: false,
|
||||
sssb: '',
|
||||
bz: ''
|
||||
}
|
||||
},
|
||||
/** 移除空值(''/null/undefined),保留 0/false 等有效值 */
|
||||
cleanPayload(obj) {
|
||||
const payload = {}
|
||||
Object.keys(obj).forEach(key => {
|
||||
const value = obj[key]
|
||||
if (value !== '' && value !== null && value !== undefined) {
|
||||
payload[key] = value
|
||||
}
|
||||
})
|
||||
return payload
|
||||
},
|
||||
isTrue(val) {
|
||||
return val === true || val === 1 || val === '1' || val === 'true'
|
||||
},
|
||||
fmtXslx(val) {
|
||||
return this.isTrue(val) ? '实教' : '非实教'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.app-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.venue-page {
|
||||
.search-card {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.search-form {
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-actions {
|
||||
padding-top: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-card {
|
||||
.list-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.list-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: 16px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.number-unit-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
|
||||
.el-input-number {
|
||||
flex: 1;
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.number-unit {
|
||||
display: inline-flex;
|
||||
flex: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 36px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
|
||||
.danger-text-btn {
|
||||
color: #f56c6c;
|
||||
|
||||
&:hover {
|
||||
color: #f78989;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user