This commit is contained in:
lijing
2026-08-12 17:19:37 +08:00
commit e73d22744e
131 changed files with 66997 additions and 0 deletions
+516
View File
@@ -0,0 +1,516 @@
<template>
<div class="group-manage-page">
<!-- 顶部操作栏 -->
<div class="top-header">
<div class="left-btn-group">
<Button type="primary" @click="openAddModal">添加</Button>
<Button type="success" style="margin-left:10px" @click="openImportModal">批量导入</Button>
</div>
<div class="right-tab-group">
<Button :type="activeType==='1'?'primary':'default'" @click="changeType('1')">年级组</Button>
<Button :type="activeType==='2'?'primary':'default'" style="margin-left:6px" @click="changeType('2')">教研组</Button>
<Button :type="activeType==='3'?'primary':'default'" style="margin-left:6px" @click="changeType('3')">备课组</Button>
</div>
</div>
<!-- 三栏主体布局 -->
<div class="three-col-container">
<!-- 左侧:分组栏 -->
<div class="col-wrap">
<h3 class="col-title">组</h3>
<div class="list-scroll-box">
<div
class="group-item"
:class="{active: selectGroupIndex === index}"
v-for="(item, index) in groupList"
:key="index"
@click="selectGroup(index)"
>
{{ item.cgName }}
</div>
</div>
<div class="col-bottom-btns">
<Button type="error" @click="delGroup">删除分组</Button>
<Button style="margin-left:8px" @click="editGroup">编辑分组</Button>
<Button type="primary">Primary</Button>
</div>
</div>
<!-- 中间:组员栏 -->
<div class="col-wrap">
<h3 class="col-title">组员</h3>
<div class="list-scroll-box">
<template v-if="groupList.length>0">
<div class="member-item" v-for="(item, idx) in groupList[selectGroupIndex].cgMember" :key="idx">
{{ item.name }}
</div>
</template>
</div>
<div class="col-bottom-btns">
<Button type="error" @click="openSetMember">设置组员</Button>
</div>
</div>
<!-- 右侧:组长栏 -->
<div class="col-wrap">
<h3 class="col-title">组长</h3>
<div class="list-scroll-box">
<template v-if="groupList.length>0">
<div class="leader-item" v-for="(item, idx) in groupList[selectGroupIndex].cgLeader" :key="idx">
{{ item.name }}
</div>
</template>
</div>
<div class="col-bottom-btns">
<Button type="error" @click="openSetLeader">设置组长</Button>
</div>
</div>
</div>
<!-- 弹窗1:添加学科 -->
<Modal v-model="addModalVisible" :title="addFormData.id?'编辑组':'添加组'" width="520">
<Form ref="addForm" :model="addFormData" label-width="90">
<FormItem label="组名">
<Input v-model="addFormData.groupName" maxlength="20" placeholder="最多可输入20个字符"/>
</FormItem>
<FormItem label="年级">
<Select v-model="addFormData.gradeIds" placeholder="请选择" style="width:100%" multiple transfer>
<Option v-for="(item,index) in gradeselectlist" :key="index" :value="item.id">{{ item.name }}</Option>
</Select>
</FormItem>
<FormItem label="学科">
<Select v-model="addFormData.subjectIds" placeholder="请选择" style="width:100%" multiple transfer>
<Option v-for="(item,index) in subjectselectlist" :key="index" :value="item.id">{{ item.name }}</Option>
</Select>
</FormItem>
</Form>
<div slot="footer" align="right">
<Button @click="addModalVisible = false">取消</Button>
<Button type="primary" @click="submitAdd">提交</Button>
</div>
</Modal>
<!-- 弹窗2:教师批量导入 -->
<Modal v-model="importModalVisible" title="批量导入分组信息" width="520">
<div class="main-contents">
<Form ref="UpParmas.datapre" :model="UpParmas.datapre" :label-width="100" inline>
<FormItem label="Excel上传:" style="margin-bottom:10px;width:100%;">
<i-input type="text" style="width:90%;" v-model="UpParmas.fileName" class="import-input" placeholder="未选中任何文件.." readonly></i-input>
<Upload class="fr btn"
:action="UpParmas.actionUrl"
:data="UpParmas.datapre"
:show-upload-list="false"
:headers="uploadHeader"
accept=".xls,.xlsx"
:before-upload="handleUpload"
:on-success="importFile"
>
<i-button icon="md-add"></i-button>
</Upload>
</FormItem>
<FormItem v-if="UpParmas.listData.data!=null" style="margin-bottom:10px">
<div v-if="UpParmas.listData.code==0" style="color:red">导入失败,请修改Excel文件中相关数据后再重新上传!</div>
<div v-if="UpParmas.listData.code!=0" style="color:green">导入成功!</div>
</FormItem>
</Form>
<Alert show-icon>
操作说明:
<Icon type="ios-bulb-outline" slot="icon" size="20"></Icon>
<template slot="desc" style="font-size: 12px;">
请先上传EXCEL文件,若成功则显示导入成功数据,否则显示错误的数据及错误原因;<br>
EXCEL文件的格式():工作表(WorkSheet)的名称应设为缺省的[Sheet1];<br>
<a @click="MoBanExceldaochu" style="font-size:12px;">点击链接下载[分组导入模板.xls]</a>
</template>
</Alert>
<Table :columns="UpParmas.columns" :data="UpParmas.listData.data" v-if="UpParmas.listData.data"></Table>
</div>
<Spin fix v-if="spinShow">
<Icon type="ios-loading" size=30 class="demo-spin-icon-load"></Icon>
<div>上传中...</div>
</Spin>
<div slot="footer">
<i-Button @click="UpfileModalcloseclick" style="margin-left: 8px">关闭</i-Button>
</div>
</Modal>
<user-check ref="userCheck" :treeData="treeData" v-model="userids" @on-submit="submit" :isDisabled="isAddto" />
<user-check ref="userCheck2" :treeData="treeData" v-model="userids2" @on-submit="submit2" :isDisabled="isAddto" />
</div>
</template>
<script>
import userCheck from "@/components/user_check.vue";
export default {
name: 'GroupTeacherManage',
components: {userCheck},
data() {
return {
// 顶部切换类型 grade年级组 / teach教研组 / prepare备课组
activeType: '1',
// 当前选中分组下标
selectGroupIndex: 0,
gradeselectlist:[],
subjectselectlist:[],
// 分组列表
groupList: [],
treeData: [],
userids: [],
userids2: [],
userNames: [],
isAddto: false,
// 添加分组弹窗
addModalVisible: false,
addFormData: {
id:'',
groupName: '',
gradeIds: [],
subjectIds: []
},
// 批量导入弹窗
importModalVisible: false,
spinShow:false,
UpParmas:{
fileName:'',
listData:{},
datapre:{},
actionUrl:APIConfig.BschClassSystem.importCustomGroup,
columns:[
{
title: '行号',
key: 'rows',
align: 'center',
width:'80'
},
{
title: '内容',
key: 'columnValue',
align: 'center',
},
{
title: '错误详情',
key: 'errorMsg',
align: 'center',
}
],
},
}
},
computed: {
uploadHeader() { //附件上传header
let config = {};
if (localStorage.getItem("currentRole")) {
let currentRole = localStorage.getItem("currentRole");
config["currentRole"] = currentRole;
}
return config;
},
},
created(){
var _this=this;
_this.treeData = [
{
name: "教师",
data: [
{
name: "基础平台",
data: _this.getTreeData2(),
}
],
},
];
},
mounted() {
this.getgradeselect();
this.getsubjectselect();
this.getSchCustomGroup();
},
methods: {
//获取年级下拉
getgradeselect:function(){
const _this = this;
var item={};
_this.$api.get(APIConfig.BschClassSystem.getgradeselect, item, resp => {
if(resp.code==0)
{
this.gradeselectlist=resp.data;
}
});
},
//获取学科下拉
getsubjectselect:function(){
const _this = this;
var item={};
_this.$api.get(APIConfig.BschClassSystem.getsubjectselect, item, resp => {
if(resp.code==0)
{
this.subjectselectlist=resp.data;
}
});
},
// 获取教师分组列表
getSchCustomGroup() {
const _this = this;
let item={
type:_this.activeType
};
_this.$api.get(APIConfig.BschClassSystem.getSchCustomGroup, item, resp => {
if (resp.code == 0) {
_this.groupList = resp.data;
} else {
_this.groupList = [];
}
});
},
// 切换顶部分组类型
changeType(type) {
this.activeType = type;
this.groupList=[];
// 此处可请求接口重新加载对应分组数据
this.getSchCustomGroup();
},
// 选中左侧分组
selectGroup(index) {
this.selectGroupIndex = index
// 模拟切换分组加载组员、组长数据
this.getSchCustomGroup();
},
// 打开添加弹窗
openAddModal() {
this.addModalVisible = true
this.addFormData = {id:'', groupName: '', grade: '', subject: '' }
},
// 提交新增分组
submitAdd() {
this.$refs.addForm.validate(valid => {
if (!valid) return
const newItem = {
groupName:this.addFormData.groupName,
groupType:this.activeType,
gradeIds:this.addFormData.gradeIds,
subjectIds:this.addFormData.subjectIds
}
if(this.addFormData.id){
newItem.id=this.addFormData.id;
}
const url = APIConfig.BschClassSystem.saveSchCustomGroup;
this.$api.post(url, JSON.stringify(newItem), resp => {
if (resp.code == 0) {
this.$Message.success(this.addFormData.id?"新增分组成功!":"保存分组成功!");
this.addModalVisible = false;
this.getSchCustomGroup();
} else if (resp.code == 4) {
this.$Message.info(resp.msg);
}
});
})
},
// 编辑分组
editGroup() {
this.addFormData.id=this.groupList[this.selectGroupIndex].cgId;
this.addFormData.groupName=this.groupList[this.selectGroupIndex].cgName;
this.addFormData.gradeIds=this.groupList[this.selectGroupIndex].gradeIds;
this.addFormData.subjectIds=this.groupList[this.selectGroupIndex].subjectIds;
this.addModalVisible=true;
},
// 删除分组
delGroup() {
this.$Modal.confirm({
title: '提示',
content: '确定删除该分组?删除后不可恢复',
onOk: () => {
let item={
groupId:this.groupList[this.selectGroupIndex].cgId
};
var url=APIConfig.BschClassSystem.deleteSchCustomGroup;
this.$api.post(url,item,(resp)=>{
this.selectGroupIndex = 0
this.$Message.success('删除成功!');
this.getSchCustomGroup();
});
}
})
},
// 设置组员
openSetMember() {
this.userids=this.groupList[this.selectGroupIndex].cgMember.map(a=>a.id);
this.$refs.userCheck.show();
},
// 设置组长
openSetLeader() {
this.userids2=this.groupList[this.selectGroupIndex].cgLeader.map(a=>a.id);
this.$refs.userCheck2.show();
},
// 设置组员确认
submit(arr) {
// if(arr.length==0){
// this.$Message.info('请选择组员!');
// return;
// }
let teaIds = arr.map(x => x.id);
let item={
groupId:this.groupList[this.selectGroupIndex].cgId,
teaIds:teaIds
};
var url=APIConfig.BschClassSystem.saveMembers;
this.$api.post(url,JSON.stringify(item),(resp)=>{
this.$Message.success('设置组员成功!');
this.getSchCustomGroup();
});
},
// 设置组长确认
submit2(arr) {
let teaIds = arr.map(x => x.id);
let item={
groupId:this.groupList[this.selectGroupIndex].cgId,
leaderIds:teaIds
};
var url=APIConfig.BschClassSystem.setLeaders;
this.$api.post(url,JSON.stringify(item),(resp)=>{
this.$Message.success('设置组长成功!');
this.getSchCustomGroup();
});
},
getTreeData2() {
return () =>
new Promise((resolve, reject) => {
this.$api.get(APIConfig.BschClassSystem.getTeacherTree, null, resp => {
console.log("请求完成!");
resolve([resp.data]);
});
});
},
// 批量导入相关
openImportModal() {
this.importModalVisible = true
},
//导入成功返回
importFile(response, file, fileList){
const _this=this;
console.log(response);
console.log(file);
_this.spinShow=false;
_this.UpParmas.fileName=file.name;
_this.UpParmas.listData=response;
if(response.State)
{
_this.$Message.info('导入成功!');
_this.getteachssearch();
}else{
_this.$Message.info(response.Message);
}
},
//附件上传之前的方法
handleUpload:function(file){
const _this=this;
_this.spinShow=true;
},
//模版导出
MoBanExceldaochu() {
var _this = this;
if (localStorage.getItem("currentRole")) {
let currentRole = localStorage.getItem("currentRole");
let { schId, roleId, userId, childId } = JSON.parse(decodeURIComponent(currentRole));
let query='?schId='+schId;
var url=APIConfig.BschClassSystem.GroupdownloadTemplate+query;
window.location.href=url;
}else{
this.$Message.info('获取不了学校!');
}
},
//附件上传模态框关闭事件
UpfileModalcloseclick:function(){
this.importModalVisible=false;
this.UpParmas={
fileName:'',
listData:{},
datapre:{},
}
},
}
}
</script>
<style scoped>
.group-manage-page {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 12px;
}
/* 顶部栏 */
.top-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 14px;
background: #f7f7f7;
border-radius: 4px;
margin-bottom: 16px;
flex-shrink: 0;
}
.left-btn-group, .right-tab-group {
display: flex;
align-items: center;
}
/* 三栏容器 */
.three-col-container {
display: flex;
flex: 1;
gap: 16px;
min-height: 0;
}
.col-wrap {
flex: 1;
border: 1px solid #e5e7eb;
display: flex;
flex-direction: column;
min-height: 0;
}
.col-title {
margin: 12px 14px;
font-size: 18px;
font-weight: bold;
flex-shrink: 0;
}
/* 滚动列表区域 */
.list-scroll-box {
flex: 1;
min-height: 0;
overflow-y: auto;
padding: 0 14px;
}
.group-item {
padding: 8px 10px;
margin: 4px 0;
cursor: pointer;
border-radius: 3px;
}
.group-item.active {
background: #9b77e9;
color: #fff;
}
.member-item, .leader-item {
padding: 6px 10px;
margin: 3px 0;
}
/* 底部按钮 */
.col-bottom-btns {
padding: 12px 14px;
border-top: 1px solid #eee;
flex-shrink: 0;
}
</style>
<style>
.ivu-alert-desc{
font-size: 12px;
}
</style>
+187
View File
@@ -0,0 +1,187 @@
<template>
<div class="page-wrap">
<!-- 顶部搜索区域 -->
<div class="top-search-bar">
<div class="placeholder-left"></div>
<Input
v-model="searchKey"
placeholder="账号、姓名、联系电话、变动详情"
style="width: 360px"
suffix="ios-search"
@on-search="handleSearch"
clearable
></Input>
</div>
<!-- 核心:表格自适应滚动容器 -->
<div class="table-scroll-box">
<Table
border
stripe
:columns="tableColumns"
:data="tableData"
class="teacher-table"
@on-selection-change="selectionChange"
:height="useTableHeight()-12"
></Table>
</div>
<!-- 分页栏:固定在底部,不会滚动 -->
<div class="page-fixed-bottom">
<span class="total-text">共 {{ total }} 条</span>
<Page
:current.sync="pageNum"
:total="total"
:page-size="pageSize"
:page-size-opts="[10,20,50]"
show-sizer
@on-change="pageChange"
@on-page-size-change="sizeChange"
></Page>
</div>
</div>
</template>
<script>
import { self_viewport } from "@/mixins/self_viewport";
export default {
name: 'TeacherChangeRecord',
data() {
return {
searchKey: '',
pageNum: 1,
pageSize: 10,
total: 52,
selectedRows: [],
tableColumns: [
{
title: '序号',
align: 'center',
width: 70,
render: (h, params) => {
const num = (this.pageNum - 1) * this.pageSize + params.index + 1
return h('span', num)
}
},
{
title: '教师账号',
key: 'account',
align: 'center'
},
{
title: '教师姓名',
key: 'name',
align: 'center'
},
{
title: '联系电话',
key: 'phone',
align: 'center'
},
{
title: '变动详情',
key: 'changeInfo',
align: 'center'
},
{
title: '变动日期',
key: 'changeDate',
align: 'center'
}
],
tableData: [
{ account: '13761014664', name: '郭秀丽', phone: '13761014664', changeInfo: '从上海市进才中学北校转出', changeDate: '2020-04-01' },
{ account: '13761040842', name: '刘莉', phone: '13761040842', changeInfo: '从上海市进才中学北校转出', changeDate: '2020-07-08' },
{ account: '13482212686', name: '万凤翠', phone: '13482212686', changeInfo: '从上海市进才中学北校转出', changeDate: '2020-07-08' },
{ account: '13681943351', name: '许娟', phone: '13681943351', changeInfo: '从上海市进才中学北校转出', changeDate: '2020-07-08' },
{ account: '18816921752', name: '许曼', phone: '18816921752', changeInfo: '从上海市进才中学北校转出', changeDate: '2020-07-08' },
{ account: '18017500305', name: '龚庆', phone: '18017500305', changeInfo: '从上海市进才中学北校转出', changeDate: '2020-07-08' },
{ account: '13901923389', name: '俞胜', phone: '13901923389', changeInfo: '从上海市进才中学北校转出', changeDate: '2020-08-30' },
{ account: '13371935731', name: '刘涵', phone: '13371935731', changeInfo: '从上海市进才中学北校教辅转出', changeDate: '2021-06-01' }
]
}
},
mixins: [self_viewport],
mounted() {
this.loadData()
},
methods: {
selectionChange(rows) {
this.selectedRows = rows
},
loadData() {
console.log('分页参数', this.pageNum, this.pageSize, this.searchKey)
// 接口请求示例
// this.$axios.get('/api/teacher/changeList', { params: { pageNum, pageSize, keyword: searchKey } }).then(res => {
// this.tableData = res.data.records
// this.total = res.data.total
// })
},
handleSearch() {
this.pageNum = 1
this.loadData()
},
pageChange(p) {
this.pageNum = p
this.loadData()
},
sizeChange(size) {
this.pageSize = size
this.pageNum = 1
this.loadData()
}
}
}
</script>
<style scoped>
/* 页面根容器:占满父高度,纵向弹性布局 */
.page-wrap {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 12px;
}
/* 顶部搜索栏 固定高度不压缩 */
.top-search-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 14px;
background: #f7f7f7;
border-radius: 4px;
margin-bottom: 12px;
flex-shrink: 0;
}
.placeholder-left {
flex: 1;
}
/* 表格区域:自动填充剩余高度,内容超出滚动 */
.table-scroll-box {
flex: 1;
min-height: 0;
}
.table-scroll-box >>> .teacher-table {
height: 100%;
}
/* 分页容器:固定在底部,禁止被压缩、不会随表格滚动 */
.page-fixed-bottom {
display: flex;
justify-content: flex-end;
align-items: center;
padding-top: 12px;
gap: 12px;
flex-shrink: 0;
}
.total-text {
font-size: 14px;
color: #333;
}
</style>
+945
View File
@@ -0,0 +1,945 @@
<template>
<div class="outer-wrap">
<div class="page-flex-layout">
<!-- 左侧分组树形栏 -->
<div class="tree-sidebar">
<div class="tree-op-buttons">
<Tooltip content="添加子组" placement="top-start">
<Button shape="circle" size="default" @click="openAddGroupModal" title="添加子组">
<Icon type="ios-add"></Icon>
</Button>
</Tooltip>
<Tooltip content="修改子组" placement="top-start">
<Button :disabled="selectnodetype==7" shape="circle" size="default" @click="openEditGroupModal" title="修改子组">
<Icon type="ios-create-outline"></Icon>
</Button>
</Tooltip>
<Tooltip content="移动子组" placement="top-start">
<Button :disabled="selectnodetype==7" shape="circle" size="default" @click="openMoveGroupModal" title="移动子组">
<Icon type="ios-folder-open"></Icon>
</Button>
</Tooltip>
<Tooltip content="删除子组" placement="top-start">
<Button :disabled="selectnodetype==7" shape="circle" size="default" @click="delCurrentGroup" title="删除子组">
<Icon type="ios-trash"></Icon>
</Button>
</Tooltip>
</div>
<my-tree :treeData="treeData" @on-tree-click="treeLink"></my-tree>
</div>
<!-- 右侧教师主体区域 -->
<div class="right-main">
<!-- 顶部操作栏 -->
<div class="top-tool-bar">
<div class="left-btn-group">
<Button :disabled="selectnodetype==7" type="primary" @click="openAddTeacherModal">添加教师</Button>
<Button type="success" style="margin-left:10px" @click="openImportModal">教师导入</Button>
</div>
<div class="search-wrap">
<Input
class="fr"
v-model="searchKeyword"
placeholder="请输入教师名字或教师账号"
search
style="width:260px"
@on-search="searchTeacher"
/>
</div>
</div>
<!-- 【修复重点容器】表格自适应区域 -->
<div class="table-adapt-wrap">
<div class="table-scroll">
<Table
border
stripe
:columns="tableColumns"
:data="tableData"
class="teacher-table"
@on-selection-change="selectionChange"
:height="useTableHeight({ isSearch: true, isOperat: true })-22"
></Table>
</div>
<!-- 分页栏:永远固定在表格底部,不跟随滚动 -->
<div class="bottom-bar">
<div class="batch-btn-group">
<Button type="error" @click="batchDeleteTeacher">删除教师</Button>
<Button style="margin-left:8px" @click="batchTransferTeacher">转出教师</Button>
<Button style="margin-left:8px" @click="openBatchMoveTeacherModal">移动教师</Button>
<Button style="margin-left:8px" @click="openSetStatusModal">设置状态</Button>
</div>
<div class="pagination-wrap">
<Page
:current.sync="pageNum"
:total="total"
:page-size="pageSize"
:page-size-opts="[10,20,50]"
show-sizer
show-total
@on-change="pageChange"
@on-page-size-change="sizeChange"
></Page>
</div>
</div>
</div>
</div>
</div>
<!-- 弹窗1:添加教师 -->
<Modal v-model="addTeacherModal" title="添加教师" width="540">
<Form ref="addTeacherForm" :model="addTeacherFormData" :rules="addTeacherRules" label-width="110">
<FormItem label="教师姓名" prop="teacherName">
<Input v-model="addTeacherFormData.teacherName" placeholder="请输入老师姓名"></Input>
</FormItem>
<FormItem label="用户名" prop="account">
<Input v-model="addTeacherFormData.account" placeholder="请输入用户名"></Input>
</FormItem>
<FormItem label="密码" prop="password">
<Input v-model="addTeacherFormData.password" placeholder="请输入密码" type="password"></Input>
</FormItem>
<FormItem label="身份证号" prop="idCard">
<Input v-model="addTeacherFormData.idCard" placeholder="请输入身份证号"></Input>
</FormItem>
<FormItem label="手机号" prop="phone">
<Input v-model="addTeacherFormData.phone" placeholder="请输入手机号"></Input>
</FormItem>
<FormItem label="性别" prop="gender">
<Select v-model="addTeacherFormData.gender" style="width:100%" transfer>
<Option value="1">男</Option>
<Option value="0">女</Option>
</Select>
</FormItem>
</Form>
<div slot="footer" align="right">
<Button @click="addTeacherModal = false" style="margin-right:10px">取消</Button>
<Button type="primary" @click="submitAddTeacher">提交</Button>
</div>
</Modal>
<!-- 弹窗2:编辑教师 -->
<Modal v-model="editTeacherModal" title="编辑教师" width="540">
<Form ref="editTeacherForm" :model="editTeacherFormData" :rules="editTeacherRules" label-width="110">
<FormItem label="教师姓名" prop="teacherName">
<Input v-model="editTeacherFormData.teacherName"></Input>
</FormItem>
<FormItem label="用户名" prop="account">
<Input v-model="editTeacherFormData.account"></Input>
</FormItem>
<FormItem label="身份证号" prop="idCard">
<Input v-model="editTeacherFormData.idCard"></Input>
</FormItem>
<FormItem label="手机号" prop="phone">
<Input v-model="editTeacherFormData.phone"></Input>
</FormItem>
<FormItem label="性别" prop="gender">
<Select v-model="editTeacherFormData.gender" style="width:100%" transfer>
<Option value="1">男</Option>
<Option value="0">女</Option>
</Select>
</FormItem>
</Form>
<div slot="footer" align="right">
<Button @click="editTeacherModal = false" style="margin-right:10px">取消</Button>
<Button type="primary" @click="submitEditTeacher">提交</Button>
</div>
</Modal>
<!-- 弹窗3:教师导入 -->
<Modal v-model="importModal" title="教师导入" width="460">
<div class="main-contents">
<Form ref="UpParmas.datapre" :model="UpParmas.datapre" :label-width="100" inline>
<FormItem label="Excel上传:" style="margin-bottom:10px;width:100%;">
<i-input type="text" style="width:90%;" v-model="UpParmas.fileName" class="import-input" placeholder="未选中任何文件.." readonly></i-input>
<Upload class="fr btn"
:action="UpParmas.actionUrl"
:data="UpParmas.datapre"
:show-upload-list="false"
:headers="uploadHeader"
accept=".xls,.xlsx"
:before-upload="handleUpload"
:on-success="importFile"
>
<i-button icon="md-add"></i-button>
</Upload>
</FormItem>
<FormItem v-if="UpParmas.listData.data!=null" style="margin-bottom:10px">
<div v-if="UpParmas.listData.code==0" style="color:red">导入失败,请修改Excel文件中相关数据后再重新上传!</div>
<div v-if="UpParmas.listData.code!=0" style="color:green">导入成功!</div>
</FormItem>
</Form>
<Alert show-icon>
操作说明:
<Icon type="ios-bulb-outline" slot="icon" size="20"></Icon>
<template slot="desc" style="font-size: 12px;">
请先上传EXCEL文件,若成功则显示导入成功数据,否则显示错误的数据及错误原因;<br>
EXCEL文件的格式():工作表(WorkSheet)的名称应设为缺省的[Sheet1];<br>
<a @click="MoBanExceldaochu" style="font-size:12px;">点击链接下载[教师导入模板.xls]</a>
</template>
</Alert>
<Table :columns="UpParmas.columns" :data="UpParmas.listData.data" v-if="UpParmas.listData.data"></Table>
</div>
<Spin fix v-if="spinShow">
<Icon type="ios-loading" size=30 class="demo-spin-icon-load"></Icon>
<div>上传中...</div>
</Spin>
<div slot="footer">
<i-Button @click="UpfileModalcloseclick" style="margin-left: 8px">关闭</i-Button>
</div>
</Modal>
<!-- 弹窗4:添加子组 -->
<Modal v-model="addGroupModal" title="添加子组" width="420">
<Form ref="addGroupForm" :model="addGroupFormData" :rules="addGroupRules" label-width="90">
<FormItem label="组名称">
<Input v-model="addGroupFormData.parentGroupName" disabled></Input>
</FormItem>
<FormItem label="子组名称" prop="groupName">
<Input v-model="addGroupFormData.groupName" placeholder="请输入组名称"></Input>
</FormItem>
<FormItem label="子组排序">
<Input v-model="addGroupFormData.sort"></Input>
</FormItem>
</Form>
<div slot="footer" align="right">
<Button @click="addGroupModal = false" style="margin-right:10px">取消</Button>
<Button type="primary" @click="submitAddGroup">提交</Button>
</div>
</Modal>
<!-- 弹窗5:修改子组 -->
<Modal v-model="editGroupModal" title="修改子组" width="420">
<Form ref="editGroupForm" :model="editGroupFormData" :rules="editGroupRules" label-width="90">
<FormItem label="子组名称" prop="groupName">
<Input v-model="editGroupFormData.groupName"></Input>
</FormItem>
<FormItem label="子组排序">
<Input v-model="editGroupFormData.sort"></Input>
</FormItem>
</Form>
<div slot="footer" align="right">
<Button @click="editGroupModal = false" style="margin-right:10px">取消</Button>
<Button type="primary" @click="submitEditGroup">提交</Button>
</div>
</Modal>
<!-- 弹窗6:移动子组 -->
<Modal v-model="moveGroupModal" title="移动子组" width="440">
<div style="margin-bottom:12px">
<span>待移动组:</span>
<Input v-model="moveGroupTargetName" disabled style="width:280px;display:inline-block;margin-left:6px"></Input>
</div>
<div style="margin-top:10px">
<span>移动至:</span>
<Tree :data="treeData" ref="moveGroupTreeRef"></Tree>
</div>
<div slot="footer" align="right">
<Button @click="moveGroupModal = false" style="margin-right:10px">取消</Button>
<Button type="primary" @click="confirmMoveGroup">确定</Button>
</div>
</Modal>
<!-- 弹窗7:批量删除确认 -->
<Modal v-model="batchDeleteModal" title="删除" width="400">
<Alert type="warning" show-icon>
确定是否删除教师?<br/>删除后将不可恢复。
</Alert>
<div slot="footer" align="right">
<Button @click="batchDeleteModal = false" style="margin-right:10px">取消</Button>
<Button type="error" @click="confirmBatchDelete">确定</Button>
</div>
</Modal>
<!-- 弹窗8:移动教师弹窗 -->
<!-- 弹窗8:移动教师弹窗(无箭头,勾选自动进右侧,右侧删除自动取消左侧勾选) -->
<Modal v-model="moveTeacherModal" title="移动教师" width="680">
<div style="margin-bottom:16px;display:flex;align-items:center;">
<span style="white-space:nowrap;margin-right:10px;">待移动教师:</span>
<Input v-model="moveTeacherName" disabled style="flex:1" />
</div>
<div style="display:flex;align-items:stretch;gap:12px;">
<!-- 左侧:选择组 zTree勾选树 -->
<div style="flex:1;border:1px solid #dcdcdc;display:flex;flex-direction:column;">
<div style="background:#3377dd;color:#fff;padding:8px 12px;text-align:center;font-weight:bold;">选择组</div>
<div style="flex:1;overflow:auto;padding:8px;">
<my-tree
ref="moveTeacherLeftTree"
:treeData="treeData"
:setting="treeSetting"
@on-tree-Check="checkedtreeLink"
></my-tree>
</div>
</div>
<!-- 中间箭头区域直接删除,不再需要 -->
<!-- 右侧:移动至组 已选列表 带单条删除 -->
<div style="flex:1;border:1px solid #dcdcdc;display:flex;flex-direction:column;">
<div style="background:#3377dd;color:#fff;padding:8px 12px;text-align:center;font-weight:bold;">移动至组</div>
<div style="flex:1;overflow:auto;padding:8px;">
<div
v-for="(item,idx) in targetGroupList"
:key="item.id"
style="padding:4px 0;display:flex;align-items:center;gap:6px;justify-content:space-between;"
>
<div style="display:flex;align-items:center;gap:6px;">
<Icon type="ios-checkbox-outline"></Icon>
<span>{{ item.name }}</span>
</div>
<Icon
type="ios-close"
style="color:#f56c6c;cursor:pointer;font-size:16px;"
@click="handleDeleteRightItem(item, idx)"
/>
</div>
<div v-if="targetGroupList.length === 0" style="color:#999;text-align:center;padding:20px 0;">暂无选中分组</div>
</div>
</div>
</div>
<div slot="footer" align="right">
<Button @click="moveTeacherModal = false" style="margin-right:10px">取消</Button>
<Button type="primary" @click="submitMoveTeacher">确定</Button>
</div>
</Modal>
<!-- 弹窗9:【设置教师的状态】 匹配设计图 -->
<Modal v-model="setStatusModal" title="设置教师的状态" width="380">
<Form ref="statusForm" :model="statusFormData" label-width="120">
<FormItem label="选择设置状态">
<RadioGroup v-model="statusFormData.status">
<Radio label="1">正常</Radio>
<Radio label="0">禁用</Radio>
</RadioGroup>
</FormItem>
</Form>
<div slot="footer" align="right">
<Button @click="setStatusModal = false" style="margin-right:10px">取消</Button>
<Button type="primary" @click="submitSetStatus">确定</Button>
</div>
</Modal>
<!-- 弹窗10:转出教师弹窗 -->
<Modal v-model="transferTeacherModal" title="转出教师" width="420">
<p>确认将选中教师做转出操作?转出后不在本校编制内</p>
<div slot="footer" align="right">
<Button @click="transferTeacherModal = false" style="margin-right:10px">取消</Button>
<Button type="primary" @click="confirmTransferTeacher">确定</Button>
</div>
</Modal>
</div>
</template>
<script>
import myTree from "../../components/my_tree";
import { self_viewport } from "@/mixins/self_viewport";
export default {
name: 'TeacherInfoManage',
components: { myTree },
data() {
return {
selectnodeid:'',
selectnodetitle: '',
selectnodetype:7,
searchKeyword: '',
selectedRows: [],
pageNum: 1,
pageSize: 20,
total: 0,
treeData: [],
// 移动教师弹窗穿梭框
checkedTreeNodes: [], // 左侧树形勾选的节点
targetGroupList: [], // 右侧移入的目标分组数组
treeSetting:{
view: {
dblClickExpand: false,
showIcon: false,
},
check: {
enable: true,
// 核心两项配置
chkboxType: {
"Y": "", // 勾选父节点 【不会】向下联动勾选子节点
"N": "" // 取消父节点 【不会】向下联动取消子节点
},
autoCheckTrigger: false
},
callback: {}
},
tableColumns: [
{ type: 'selection', width: 50 },
{ title: '序号', type: 'index', align: 'center', width: 70 },
{ title: '教师账号', key: 'account', align: 'center' },
{ title: '教师姓名', key: 'name', align: 'center' },
{
title: '教师组',
key: 'groupName',
align: 'center',
render: (h, params) => {
return h('div', [
params.row.groupList.map(a=>a.name).join(',')
]);
},
},
{ title: '联系电话', key: 'tel', align: 'center' },
{
title: '性别',
key: 'gender',
align: 'center',
width: 70,
render: (h, params) => {
return h('div', [
params.row.gender==0?'女':params.row.gender==1?'男':''
]);
},
},
{ title: '状态', key: 'statusName', align: 'center', width: 80 },
{
title: '操作',
key: 'action',
align: 'center',
width: 90,
render: (h, params) => {
return h('Button', {
props: { type: 'text', icon: 'md-create', size: 'large' },
on: { click: () => this.editSingleTeacher(params.row, params.index) }
})
}
}
],
tableData: [],
spinShow:false,
UpParmas:{
fileName:'',
listData:{},
datapre:{},
actionUrl:APIConfig.BschClassSystem.teacherImport,
columns:[
{
title: '行号',
key: 'rows',
align: 'center',
width:'80'
},
{
title: '内容',
key: 'columnValue',
align: 'center',
},
{
title: '错误详情',
key: 'errorMsg',
align: 'center',
}
],
},
addTeacherModal: false,
editTeacherModal: false,
importModal: false,
addGroupModal: false,
editGroupModal: false,
moveGroupModal: false,
batchDeleteModal: false,
moveTeacherModal: false,
setStatusModal: false,
transferTeacherModal: false,
addTeacherFormData: { teacherName: '', account: '', password: '', idCard: '', phone: '', gender: '0' },
addTeacherRules: {
teacherName: [{ required: true, message: '请输入教师姓名', trigger: 'blur' }],
account: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
gender: [{ required: true, message: '请选择性别', trigger: 'change' }]
},
editTeacherIndex: null,
editTeacherFormData: {id:null, teacherName: '', account: '', idCard: '', phone: '', gender: '0',teaId:0,status:1 },
editTeacherRules: {
teacherName: [{ required: true, message: '请输入教师姓名', trigger: 'blur' }],
account: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
gender: [{ required: true, message: '请选择性别', trigger: 'change' }]
},
addGroupFormData: { parentGroupName: '', groupName: '', sort: '' },
addGroupRules: { groupName: [{ required: true, message: '请输入子组名称', trigger: 'blur' }] },
editGroupIndex: null,
editGroupFormData: { groupName: '', sort: '' },
editGroupRules: { groupName: [{ required: true, message: '请输入子组名称', trigger: 'blur' }] },
moveGroupTargetName: '',
moveTeacherName: '',
statusFormData: { status: '1' }
}
},
mixins: [self_viewport],
computed: {
uploadHeader() { //附件上传header
let config = {};
if (localStorage.getItem("currentRole")) {
let currentRole = localStorage.getItem("currentRole");
config["currentRole"] = currentRole;
}
return config;
},
},
created() {
this.getTeaTree();
},
methods: {
//获取教师树
getTeaTree:function(){
const _this = this;
var item={};
_this.$api.get(APIConfig.BschClassSystem.getTeaTree, item, resp => {
if(resp.code==0)
{
_this.treeData=resp.data;
_this.selectnodeid=resp.data.id;
_this.selectnodetitle=resp.data.name;
_this.selectnodetype=resp.data.type;
_this.loadData();
}
});
},
// 树形选中切换
treeLink(treeNode) {
this.selectnodeid=treeNode.id;
this.selectnodetitle=treeNode.name;
this.selectnodetype=treeNode.type;
this.pageNum = 1
this.loadData()
},
// 移动教师树形复选框勾选回调(接收my-tree抛出的zTree选中数组)移动教师树形选中切换
checkedtreeLink(allCheckedList){
this.checkedTreeNodes = [...allCheckedList]
// 右侧列表 = 只保留当前左侧还在勾选的条目,自动过滤取消勾选项
this.targetGroupList = this.targetGroupList.filter(rightItem => {
return allCheckedList.some(leftItem => leftItem.id === rightItem.id)
})
// 新增左侧新勾选的节点,去重加入右侧
allCheckedList.forEach(node => {
const exist = this.targetGroupList.some(item => item.id === node.id)
if (!exist) {
this.targetGroupList.push({
id: node.id,
name: node.name
})
}
})
},
// 加载列表数据
loadData() {
const _this = this;
var item = {
groupId:_this.selectnodeid,
keyword:_this.searchKeyword,
page:_this.pageNum-1,
size:_this.pageSize
};
_this.$api.get(APIConfig.BschClassSystem.getteachersearch, item, resp => {
if (resp.code == 0) {
_this.tableData = resp.data.content;
_this.total=resp.data.total;
} else {
_this.tableData = [];
}
});
},
selectionChange(rows) {
this.selectedRows = rows
},
searchTeacher() {
this.pageNum = 1;
this.loadData();
},
pageChange(p) { this.pageNum = p;this.loadData(); },
sizeChange(s) { this.pageSize = s; this.pageNum = 1;this.loadData(); },
openAddTeacherModal() {
this.addTeacherFormData = { teacherName: '', account: '', password: '', idCard: '', phone: '', gender: '0' }
this.addTeacherModal = true
},
submitAddTeacher() {
this.$refs.addTeacherForm.validate(valid => {
if (!valid) return
// 新增
const newItem = {
groupId:this.selectnodeid,
name:this.addTeacherFormData.teacherName,
account:this.addTeacherFormData.account,
pwd:this.addTeacherFormData.password,
idCard:this.addTeacherFormData.idCard,
tel:this.addTeacherFormData.phone,
gender:this.addTeacherFormData.gender,
teaId:0,
status:1
}
const url = APIConfig.BschClassSystem.teachersave;
this.$api.post(url, JSON.stringify(newItem), resp => {
if (resp.code == 0) {
this.$Message.success("新增教师成功!");
this.addTeacherModal = false
this.loadData();
} else if (resp.code == 4) {
this.$Message.info(resp.msg);
}
});
})
},
editSingleTeacher(row, idx) {
this.editTeacherIndex = idx;
this.editTeacherFormData = {
id:row.id,
teacherName: row.name,
account: row.account,
idCard: row.idCard || '',
phone: row.tel,
gender: row.gender+'',
teaId:row.teaId,
status:row.status
};
this.editTeacherModal = true;
},
submitEditTeacher() {
this.$refs.editTeacherForm.validate(valid => {
if (!valid) return
// 编辑
const newItem = {
id:this.editTeacherFormData.id,
groupId:this.selectnodeid,
name:this.editTeacherFormData.teacherName,
account:this.editTeacherFormData.account,
idCard:this.editTeacherFormData.idCard,
tel:this.editTeacherFormData.phone,
gender:this.editTeacherFormData.gender,
teaId:this.editTeacherFormData.teaId,
status:this.editTeacherFormData.status
}
const url = APIConfig.BschClassSystem.teachersave;
this.$api.post(url, JSON.stringify(newItem), resp => {
if (resp.code == 0) {
this.$Message.success("编辑教师成功!");
this.editTeacherModal = false
this.loadData();
} else if (resp.code == 4) {
this.$Message.info(resp.msg);
}
});
})
},
openImportModal() { this.importModal = true },
//导入成功返回
importFile(response, file, fileList){
const _this=this;
console.log(response);
console.log(file);
_this.spinShow=false;
_this.UpParmas.fileName=file.name;
_this.UpParmas.listData=response;
if(response.State)
{
_this.$Message.info('导入成功!');
_this.getsearcBaseSchClass();
}else{
_this.$Message.info(response.Message);
}
},
//附件上传之前的方法
handleUpload:function(file){
const _this=this;
_this.spinShow=true;
},
MoBanExceldaochu() {
var _this = this;
if (localStorage.getItem("currentRole")) {
let currentRole = localStorage.getItem("currentRole");
let { schId, roleId, userId, childId } = JSON.parse(decodeURIComponent(currentRole));
var url=APIConfig.BschClassSystem.teacherdownloadTemplate+'?schId='+schId;
window.location.href=url;
}else{
this.$Message.info('获取不了学校!');
}
},
//附件上传模态框关闭事件
UpfileModalcloseclick:function(){
this.importModal=false;
this.UpParmas={
fileName:'',
listData:{},
datapre:{},
}
},
batchDeleteTeacher() {
if (!this.selectedRows.length) return this.$Message.warning('请先勾选教师')
this.batchDeleteModal = true
},
confirmBatchDelete() {
const idlist = this.selectedRows.map(i => i.id);
const url = APIConfig.BschClassSystem.teacherdelete+idlist.join(',');
this.$api.post(url,{}, resp => {
if (resp.code == 0) {
this.$Message.success("删除成功!");
this.selectedRows = [];
this.batchDeleteModal = false;
this.loadData();
} else if (resp.code == 4) {
this.$Message.info(resp.msg);
}
});
},
// 弹窗打开初始化
openBatchMoveTeacherModal() {
if (!this.selectedRows.length) return this.$Message.warning('请先勾选教师')
this.moveTeacherName = this.selectedRows.map(i => i.name).join('、')
// 清空数据
this.checkedTreeNodes = []
this.targetGroupList = []
this.$nextTick(() => {
// 清空整棵树所有勾选
const ztree = this.$refs.moveTeacherLeftTree.getZtreeInstance()
ztree.checkAllNodes(false)
})
this.moveTeacherModal = true
},
// 右侧点击X删除单条 → 反向取消左侧树勾选
handleDeleteRightItem(delItem, index) {
// 删除右侧数组
this.targetGroupList.splice(index, 1)
// 获取树实例,取消对应节点复选框
const ztree = this.$refs.moveTeacherLeftTree.getZtreeInstance()
const targetNode = ztree.getNodeByParam('id', delItem.id)
if (targetNode) {
ztree.checkNode(targetNode, false, false)
}
},
// 确定按钮 直接提交
submitMoveTeacher() {
if (this.targetGroupList.length === 0) {
return this.$Message.warning('请至少选择一个目标分组')
}
const teacherIdArr = this.selectedRows.map(row => row.id)
const groupIdArr = this.targetGroupList.map(item => item.id)
// console.log('待移动教师ID', teacherIdArr)
// console.log('目标分组ID', groupIdArr)
let item={
ids:teacherIdArr,
transferGroupIds:groupIdArr
};
const url = APIConfig.BschClassSystem.moveGroup;
this.$api.post(url,JSON.stringify(item), resp => {
if (resp.code == 0) {
this.$Message.success('教师移动分组成功');
this.moveTeacherModal = false;
// 清空选择缓存
this.selectedRows = [];
this.targetGroupList = [];
this.checkedTreeNodes = [];
// 刷新表格数据
this.loadData();
} else if (resp.code == 4) {
this.$Message.info(resp.msg);
}
});
},
batchTransferTeacher() {
if (!this.selectedRows.length) return this.$Message.warning('请先勾选教师')
this.transferTeacherModal = true
},
//转出事件
confirmTransferTeacher() {
const idlist = this.selectedRows.map(i => i.id);
const url = APIConfig.BschClassSystem.transferOut+idlist.join(',');
this.$api.post(url,{}, resp => {
if (resp.code == 0) {
this.$Message.success("转出操作完成!");
this.selectedRows = [];
this.transferTeacherModal = false;
this.loadData();
} else if (resp.code == 4) {
this.$Message.info(resp.msg);
}
});
},
openBatchMoveTeacherModal() {
if (!this.selectedRows.length) return this.$Message.warning('请先勾选教师')
this.moveTeacherName = this.selectedRows.map(i => i.name).join('、')
this.moveTeacherModal = true
},
confirmMoveTeacher() {
this.moveTeacherModal = false
this.$Message.success('移动教师成功')
},
openSetStatusModal() {
if (!this.selectedRows.length) return this.$Message.warning('请先勾选教师')
this.statusFormData.status = '1'
this.setStatusModal = true
},
submitSetStatus() {
const idlist = this.selectedRows.map(i => i.id);
let item={
ids:idlist.join(','),
status:this.statusFormData.status
};
const url = APIConfig.BschClassSystem.teachersetStatus;
this.$api.post(url,item, resp => {
if (resp.code == 0) {
this.$Message.success("状态修改成功!");
this.selectedRows = [];
this.setStatusModal = false;
this.loadData();
} else if (resp.code == 4) {
this.$Message.info(resp.msg);
}
});
},
openAddGroupModal() {
if (!this.selectnodeid) return this.$Message.warning('请先选择父分组')
this.addGroupFormData.parentGroupName = this.selectnodetitle
this.addGroupFormData.groupName = ''
this.addGroupFormData.sort = ''
this.addGroupModal = true
},
submitAddGroup() {
this.$refs.addGroupForm.validate(valid => {
if (!valid) return;
this.$Message.success('新增分组成功');
this.addGroupModal = false;
})
},
openEditGroupModal() {
if (!this.selectnodeid) return this.$Message.warning('请先选择分组')
this.editGroupIndex = this.selectnodeid;
this.editGroupFormData.groupName = this.selectnodetitle;
this.editGroupFormData.sort = '';
this.editGroupModal = true;
},
submitEditGroup() {
this.$refs.editGroupForm.validate(valid => {
if (!valid) return
this.selectedTreeNode.title = this.editGroupFormData.groupName
this.editGroupModal = false
this.$Message.success('修改分组成功')
})
},
openMoveGroupModal() {
if (!this.selectnodeid) return this.$Message.warning('请先选择分组')
this.moveGroupTargetName = this.selectnodetitle
this.moveGroupModal = true
},
confirmMoveGroup() {
this.moveGroupModal = false
this.$Message.success('移动分组成功')
},
delCurrentGroup() {
if (!this.selectnodeid) return this.$Message.warning('请先选择分组')
this.$Modal.confirm({
title: '提示',
content: `确定删除分组【${this.selectedTreeNode.title}】?`,
onOk: () => {
this.$Message.success('删除分组成功')
}
})
}
}
}
</script>
<style scoped>
/* 全局布局逐级修复高度 + min-height:0 解决flex塌陷 */
.outer-wrap {
border: 1px solid #e5e7eb;
border-radius: 4px;
padding: 16px;
width: 100%;
height: 100%;
box-sizing: border-box;
background: #fff;
display: flex;
flex-direction: column;
overflow-y: auto;
}
.page-flex-layout {
display: flex;
flex: 1;
gap: 16px;
min-height: 0; /* 第一层修复 */
}
.tree-sidebar {
width: 250px;
border: 1px solid #e8e8e8;
display: flex;
flex-direction: column;
min-height: 0;
}
.tree-op-buttons {
padding: 8px;
display: flex;
gap: 8px;
border-bottom: 1px solid #eee;
}
.tree-sidebar >>> .ivu-tree {
flex: 1;
overflow-y: auto;
padding: 8px;
}
.right-main {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0; /* 第二层修复 */
}
.top-tool-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0px 16px;
background: #f7f7f7;
margin-bottom: 16px;
flex-shrink: 0;
}
.table-adapt-wrap {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0; /* 第三层核心修复 */
}
.table-scroll {
flex: 1;
min-height: 0;
}
.teacher-table {
height: 100%;
}
/* 分页固定底部,永远不参与滚动 */
.bottom-bar {
margin-top: 16px;
display: flex;
justify-content: space-between;
align-items: center;
flex-shrink: 0;
}
.total-text {
font-size: 14px;
color: #666;
margin-right: 12px;
}
</style>
<style>
.ivu-alert-desc{
font-size: 12px;
}
</style>
+537
View File
@@ -0,0 +1,537 @@
<template>
<div class="teach-manage-page">
<!-- 顶部筛选栏 -->
<div class="top-filter-bar">
<div class="filter-left">
<Select v-model="majorVal" placeholder="选择学制" style="width: 220px" @on-change="getselectBySchsystemId">
<Option v-for="(item,index) in schsystemselectlist" :key="index" :value="item.id">{{ item.name }}</Option>
</Select>
<Select v-model="gradeVal" placeholder="选择年级" style="width: 180px; margin-left: 12px" @on-change="handleGradeChange">
<Option v-for="(item,index) in selectBySchsystemIdlist" :key="index" :value="item.id">{{ item.name }}</Option>
</Select>
</div>
<div class="btn-group-right">
<Button type="success" @click="handleBatchImport">批量导入</Button>
<Button type="success" style="margin-left: 10px" @click="handleExport">任教导出</Button>
</div>
</div>
<!-- 关键外层嵌套:强制横向溢出滚动 -->
<div class="table-outer">
<Table
border
stripe
:columns="tableColumns"
:data="tableData"
:height="useTableHeight()+48"
></Table>
</div>
<!-- 选择教师弹窗 -->
<Modal v-model="teacherModalVisible" title="选择教师" width="420" @on-cancel="resetModal">
<div style="padding:10px 20px;">
<div style="margin-bottom:18px;">
<span style="display:inline-block;width:60px;">科室</span>
<Select v-model="selectDept" placeholder="按科室过滤" style="width:280px" @on-change="getteacherSelect" clearable>
<Option v-for="item in groupteacherSelectlist" :key="item.id" :value="item.id">{{ item.name }}</Option>
</Select>
</div>
<div>
<span style="display:inline-block;width:60px;">教师</span>
<Select v-model="selectTeacher" placeholder="请选择" style="width:280px" filterable>
<Option v-for="item in teacherSelectlist" :key="item.id" :value="item.id">{{ item.name }}</Option>
</Select>
</div>
</div>
<div slot="footer" align="right">
<Button @click="teacherModalVisible = false">取消</Button>
<Button type="primary" @click="submitSelectTeacher">提交</Button>
</div>
</Modal>
<!-- 批量导入弹窗 -->
<Modal v-model="importModalVisible" title="批量导入任教信息" width="520">
<div class="main-contents">
<Form ref="UpParmas.datapre" :model="UpParmas.datapre" :label-width="100" inline>
<FormItem label="Excel上传:" style="margin-bottom:10px;width:100%;">
<i-input type="text" style="width:90%;" v-model="UpParmas.fileName" class="import-input" placeholder="未选中任何文件.." readonly></i-input>
<Upload class="fr btn"
:action="UpParmas.actionUrl"
:data="UpParmas.datapre"
:show-upload-list="false"
:headers="uploadHeader"
accept=".xls,.xlsx"
:before-upload="handleUpload"
:on-success="importFile"
>
<i-button icon="md-add"></i-button>
</Upload>
</FormItem>
<FormItem v-if="UpParmas.listData.data!=null" style="margin-bottom:10px">
<div v-if="UpParmas.listData.code==0" style="color:red">导入失败,请修改Excel文件中相关数据后再重新上传!</div>
<div v-if="UpParmas.listData.code!=0" style="color:green">导入成功!</div>
</FormItem>
</Form>
<Alert show-icon>
操作说明:
<Icon type="ios-bulb-outline" slot="icon" size="20"></Icon>
<template slot="desc" style="font-size: 12px;">
请先上传EXCEL文件,若成功则显示导入成功数据,否则显示错误的数据及错误原因;<br>
EXCEL文件的格式():工作表(WorkSheet)的名称应设为缺省的[Sheet1];<br>
<a @click="MoBanExceldaochu" style="font-size:12px;">点击链接下载[任教导入模板.xls]</a>
</template>
</Alert>
<Table :columns="UpParmas.columns" :data="UpParmas.listData.data" v-if="UpParmas.listData.data"></Table>
</div>
<Spin fix v-if="spinShow">
<Icon type="ios-loading" size=30 class="demo-spin-icon-load"></Icon>
<div>上传中...</div>
</Spin>
<div slot="footer">
<i-Button @click="UpfileModalcloseclick" style="margin-left: 8px">关闭</i-Button>
</div>
</Modal>
</div>
</template>
<script>
import { self_viewport } from "@/mixins/self_viewport";
export default {
name: 'TeachManage',
mixins: [self_viewport],
data() {
return {
majorVal: '',
gradeVal: '',
importModalVisible: false,
schsystemselectlist: [],
selectBySchsystemIdlist: [],
// 后端原始数据源
subjectList: [],
classList: [],
teachList: [],
tableColumns: [],
tableData: [],
teacherModalVisible: false,
currentRowIndex: null,
currentSubId: '',
currentClassId: null,
oldTeacherId: null,
detailId: null, // 任教明细主键id
selectDept: '',
selectTeacher: '',
groupteacherSelectlist: [],
teacherSelectlist: [],
spinShow:false,
UpParmas:{
fileName:'',
listData:{},
datapre:{},
actionUrl:APIConfig.BschClassSystem.teacherImport,
columns:[
{
title: '行号',
key: 'rows',
align: 'center',
width:'80'
},
{
title: '内容',
key: 'columnValue',
align: 'center',
},
{
title: '错误详情',
key: 'errorMsg',
align: 'center',
}
],
},
}
},
computed: {
uploadHeader() { //附件上传header
let config = {};
if (localStorage.getItem("currentRole")) {
let currentRole = localStorage.getItem("currentRole");
config["currentRole"] = currentRole;
}
return config;
},
},
created() {
this.getschsystemselect();
this.getgroupteacherSelect();
this.getteacherSelect();
},
methods: {
// 学制下拉
getschsystemselect() {
const _this = this;
_this.$api.get(APIConfig.BschClassSystem.getschsystemselect, {}, resp => {
if (resp.code == 0) {
_this.schsystemselectlist = resp.data;
if (_this.schsystemselectlist.length > 0) {
_this.majorVal = _this.schsystemselectlist[0].id;
_this.getselectBySchsystemId();
}
} else {
_this.schsystemselectlist = [];
}
});
},
// 通过学制ID获取年级下拉
getselectBySchsystemId() {
const _this = this;
const item = { schsystemId: _this.majorVal };
_this.$api.get(APIConfig.BschClassSystem.getselectBySchsystemId, item, resp => {
if (resp.code == 0) {
_this.selectBySchsystemIdlist = resp.data;
_this.getteachssearch();
} else {
_this.selectBySchsystemIdlist = [];
}
});
},
// 教师组下拉
getgroupteacherSelect() {
const _this = this;
_this.$api.get(APIConfig.BschClassSystem.getgroupteacherSelect, {}, resp => {
if (resp.code == 0) {
_this.groupteacherSelectlist = resp.data;
} else {
_this.groupteacherSelectlist = [];
}
});
},
// 教师下拉
getteacherSelect() {
const _this = this;
const item = { groupId: _this.selectDept };
_this.$api.get(APIConfig.BschClassSystem.getteacherSelect, item, resp => {
if (resp.code == 0) {
_this.teacherSelectlist = resp.data;
if (_this.oldTeacherId) {
const findT = _this.teacherSelectlist.find(t => t.id === _this.oldTeacherId);
if (findT) {
_this.selectTeacher = findT.id;
}
}
} else {
_this.teacherSelectlist = [];
}
});
},
// 打开弹窗并回显原有教师+明细ID
openTeacherModal(rowIdx, rowData, subId) {
this.resetModal();
this.currentRowIndex = rowIdx;
this.currentSubId = subId;
this.currentClassId = rowData.classId;
this.detailId = null;
const classTeach = this.teachList.find(item => item.classId === this.currentClassId);
if (classTeach) {
const subItem = classTeach.teachSubjectList.find(s => s.subId === subId);
if (subItem) {
this.oldTeacherId = subItem.teacherId || null;
this.detailId = subItem.id;
}
}
this.teacherModalVisible = true;
this.getteacherSelect();
},
// 核心:获取任教列表并格式化表格数据 + 自动生成表头
getteachssearch() {
const _this = this;
const item = {
schsystemId: this.majorVal,
gradeId: this.gradeVal
};
_this.$api.get(APIConfig.BschClassSystem.getteachssearch, item, resp => {
if (resp.code !== 0) {
_this.subjectList = [];
_this.classList = [];
_this.teachList = [];
_this.tableData = [];
_this.tableColumns = [];
return;
}
const { subjectList, classList, teachList } = resp.data;
_this.subjectList = subjectList;
_this.classList = classList;
_this.teachList = teachList;
// 组装表格行数据:一行一个班级,key=subId
_this.tableData = _this.classList.map(classItem => {
const matchTeach = _this.teachList.find(t => t.classId === classItem.classId);
const row = {
gradeId:classItem.gradeId,
grade: classItem.gradeName,
className: classItem.name,
classId: classItem.classId
};
if (matchTeach && Array.isArray(matchTeach.teachSubjectList)) {
matchTeach.teachSubjectList.forEach(subItem => {
row[subItem.subId] = subItem.teacherName || '';
});
}
return row;
});
// 动态构建列
_this.buildTableColumns();
});
},
// 动态生成表格列(完全基于后端subjectList,无硬编码科目)
buildTableColumns() {
// 左侧固定列
const baseColumns = [
{ title: '年级', key: 'grade', fixed: 'left', width: 110, align: 'center' },
{ title: '班级', key: 'className', fixed: 'left', width: 110, align: 'center' }
];
// 科目动态列
const subjectColumns = this.subjectList.map(subItem => {
const subId = subItem.id;
const subName = subItem.name;
return {
title: subName,
key: subId,
width: 180,
align: 'center',
render: (h, params) => {
const val = params.row[subId];
return h('div', {
style: {
display: 'flex',
alignItems: 'center',
width: '140px',
height: '34px',
border: '1px solid #dcdcdc',
borderRadius: '4px',
cursor: 'pointer',
margin: '0 auto'
},
on: {
click: () => {
this.openTeacherModal(params.index, params.row, subId)
}
}
}, [
h('span', {
style: {
flex: 1,
textAlign: 'center',
fontSize: '14px',
paddingLeft: '6px',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}
}, val || '点击选择'),
val ? h('span', {
style: {
width: '22px',
height: '22px',
lineHeight: '22px',
textAlign: 'center',
color: 'red',
borderLeft: '1px solid #eee',
flexShrink: 0,
fontSize: '14px',
cursor: 'pointer'
},
on: {
click: (e) => {
e.stopPropagation();
const row = params.row;
let delId = null;
const classTeach = this.teachList.find(t => t.classId === row.classId);
if (classTeach) {
const target = classTeach.teachSubjectList.find(s => s.subId === subId);
delId = target?.id;
}
this.$api.post(APIConfig.BschClassSystem.teachsdelete+delId, {}, res => {
if (res.code === 0) {
this.$Message.success('移除教师成功');
this.getteachssearch();
}
});
}
}
}, '×') : null
]);
}
};
});
// 右侧操作列
const actionColumn = [{
title: '操作',
key: 'action',
fixed: 'right',
width: 80,
align: 'center',
render: (h, params) => {
return h('Button', {
props: { type: 'text', icon: 'ios-refresh', size: 'large' },
attrs: { title: '重置本行所有任教' },
on: { click: () => this.handleResetRow(params.index) }
})
}
}];
this.tableColumns = [...baseColumns, ...subjectColumns, ...actionColumn];
},
// 弹窗提交分配教师
submitSelectTeacher() {
if (!this.selectTeacher) {
this.$Message.warning('请选择教师');
return;
}
const row = this.tableData[this.currentRowIndex];
const params = {
id: this.detailId,
gradeId:row.gradeId,
classId: row.classId,
subId: this.currentSubId,
teaId: this.selectTeacher
};
this.$api.post(APIConfig.BschClassSystem.teachssave, JSON.stringify(params), res => {
if (res.code === 0) {
this.$Message.success('分配教师成功');
this.teacherModalVisible = false;
this.getteachssearch();
}
});
},
// 关闭弹窗重置变量
resetModal() {
this.selectDept = '';
this.selectTeacher = '';
this.currentRowIndex = null;
this.currentSubId = '';
this.currentClassId = null;
this.oldTeacherId = null;
this.detailId = null;
},
// 整行重置清空所有科目教师
handleResetRow(index) {
this.$Modal.confirm({
title: '提示',
content: '确定清空该班级所有学科任教教师?',
onOk: () => {
const row = this.tableData[index];
const params = {
classId: row.classId
};
this.$api.post(APIConfig.BschClassSystem.delClassTeach, params, res => {
if (res.code === 0) {
this.getteachssearch();
this.$Message.success('重置完成');
}
});
}
});
},
handleGradeChange() {
this.getteachssearch();
},
handleBatchImport() {
this.importModalVisible = true;
},
//导入成功返回
importFile(response, file, fileList){
const _this=this;
console.log(response);
console.log(file);
_this.spinShow=false;
_this.UpParmas.fileName=file.name;
_this.UpParmas.listData=response;
if(response.State)
{
_this.$Message.info('导入成功!');
_this.getteachssearch();
}else{
_this.$Message.info(response.Message);
}
},
//附件上传之前的方法
handleUpload:function(file){
const _this=this;
_this.spinShow=true;
},
MoBanExceldaochu() {
var _this = this;
if (localStorage.getItem("currentRole")) {
let currentRole = localStorage.getItem("currentRole");
let { schId, roleId, userId, childId } = JSON.parse(decodeURIComponent(currentRole));
let query=this.gradeVal?'?schId='+schId+'&schsystemId='+this.majorVal+'&gradeId='+this.gradeVal:'?schId='+schId+'&schsystemId='+this.majorVal;
var url=APIConfig.BschClassSystem.TeachdownloadTemplate+query;
window.location.href=url;
}else{
this.$Message.info('获取不了学校!');
}
},
//附件上传模态框关闭事件
UpfileModalcloseclick:function(){
this.importModalVisible=false;
this.UpParmas={
fileName:'',
listData:{},
datapre:{},
}
},
handleExport() {
var _this = this;
if (localStorage.getItem("currentRole")) {
let currentRole = localStorage.getItem("currentRole");
let { schId, roleId, userId, childId } = JSON.parse(decodeURIComponent(currentRole));
let query=this.gradeVal?'?schId='+schId+'&schsystemId='+this.majorVal+'&gradeId='+this.gradeVal:'?schId='+schId+'&schsystemId='+this.majorVal;
var url=APIConfig.BschClassSystem.teachsexport+query;
window.location.href=url;
}else{
this.$Message.info('获取不了学校!');
}
}
}
}
</script>
<style scoped>
.teach-manage-page {
width: 100%;
padding: 10px;
box-sizing: border-box;
}
.top-filter-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
background-color: #f7f7f7;
margin-bottom: 10px;
}
.filter-left, .btn-group-right {
display: flex;
align-items: center;
}
.table-outer {
width: 100%;
overflow-x: auto;
}
</style>
<style>
.ivu-alert-desc{
font-size: 12px;
}
</style>