Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk into zdg
This commit is contained in:
commit
beca8c21b6
|
@ -22,6 +22,7 @@
|
|||
"@electron-toolkit/preload": "^3.0.1",
|
||||
"@electron-toolkit/utils": "^3.0.0",
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"@vitejs/plugin-vue-jsx": "^4.0.0",
|
||||
"@vueuse/core": "^10.11.0",
|
||||
"crypto-js": "^4.2.0",
|
||||
"electron-dl-manager": "^3.0.0",
|
||||
|
@ -37,8 +38,9 @@
|
|||
"pinia": "^2.1.7",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"spark-md5": "^3.0.2",
|
||||
"vue-cropper": "^1.0.3",
|
||||
"vue-router": "^4.4.0"
|
||||
"vue-cropper": "^1.1.4",
|
||||
"vue-router": "^4.4.0",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-toolkit/eslint-config": "^1.0.2",
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
// 查询evaluation列表
|
||||
import request from '@/utils/request'
|
||||
// 查询班级列表
|
||||
export function listClassmain(query) {
|
||||
return request({
|
||||
url: '/education/classmain/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
// 查询学生列表
|
||||
export function listClassuser(query) {
|
||||
return request({
|
||||
url: '/education/classuser/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
// 新增班级
|
||||
export function addClassmain(data) {
|
||||
return request({
|
||||
url: '/education/classmain',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
// 查询所有学科的列表
|
||||
export function listEvaluation(query) {
|
||||
return request({
|
||||
url: '/education/evaluation/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
// 新增小组
|
||||
export function addClassgroup(data) {
|
||||
return request({
|
||||
url: '/education/classgroup',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
//班级详情
|
||||
export function getClassmain(id) {
|
||||
return request({
|
||||
url: '/education/classmain/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 获取小组列表
|
||||
export function listClassgroup(query) {
|
||||
return request({
|
||||
url: '/education/classgroup/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
//删除小组
|
||||
export function delClassgroup(id) {
|
||||
return request({
|
||||
url: '/education/classgroup/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
//查询小组信息
|
||||
export function getClassgroup(id) {
|
||||
return request({
|
||||
url: '/education/classgroup/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
//修改小组信息
|
||||
export function updateClassgroup(data) {
|
||||
return request({
|
||||
url: '/education/classgroup',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
//新增学生
|
||||
export function addStudentmain(data) {
|
||||
return request({
|
||||
url: '/education/studentmain',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
//修改学生信息
|
||||
export function updateStudentmain(data) {
|
||||
return request({
|
||||
url: '/education/studentmain',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
//获取学生信息
|
||||
export function getStudentmain(id) {
|
||||
return request({
|
||||
url: '/education/studentmain/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
//删除学生
|
||||
export function leaveClass(data) {
|
||||
return request({
|
||||
url: '/education/classuser/leaveClass',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
//删除学生所有数据
|
||||
export function removeStudentDataAll(id) {
|
||||
return request({
|
||||
url: '/education/studentmain/removeStudent/' + id,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
//删除教室
|
||||
export function delClassroom(id) {
|
||||
return request({
|
||||
url: '/education/classroom/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
//导入学生
|
||||
export function addStudentmainByNameArray(data) {
|
||||
return request({
|
||||
url: '/education/studentmain/addByNameArray',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<div class="update-avatar">
|
||||
<img :src="image" ref="imgRef" />
|
||||
<div class="toolbar">
|
||||
<span @click="handleClose">取消</span>
|
||||
<!-- 实时预览 -->
|
||||
<div class="view"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import 'cropperjs/dist/cropper.css';
|
||||
import Cropper from 'cropperjs';
|
||||
const props = defineProps({
|
||||
image: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const imgRef = ref(null);
|
||||
const cropper = ref(null);
|
||||
|
||||
const handleClose = () => {
|
||||
// 你的关闭逻辑
|
||||
};
|
||||
|
||||
const cropperInit = () => {
|
||||
const image = imgRef.value;
|
||||
cropper.value = new Cropper(image, {
|
||||
aspectRatio: 1,
|
||||
dragMode: 'move',
|
||||
background: false,
|
||||
preview: '.view'
|
||||
});
|
||||
};
|
||||
|
||||
const onConfirm = () => {
|
||||
cropper.value.getCroppedCanvas().toBlob(blob => {
|
||||
// 你的确认逻辑
|
||||
console.log('blob', blob);
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
cropperInit();
|
||||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
.update-avatar {
|
||||
width: 170px;
|
||||
height: 100px;
|
||||
border: 1px blue solid;
|
||||
|
||||
}
|
||||
.update-avatar img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.update-avatar .view {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 1px black solid;
|
||||
}
|
||||
.view {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
overflow: hidden; /*这个超出设置为隐藏很重要,否则就会整个显示出来了*/
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<template>
|
||||
<el-select v-model="modelValue" v-bind="$attrs" :placeholder="placeholder">
|
||||
<slot></slot>
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, defineProps, onMounted, defineEmits } from 'vue';
|
||||
const placeholder = ref('')
|
||||
|
||||
const props = defineProps({
|
||||
statement:String,
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
placeholder.value = props.statement || "请选择"
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
const modelValue = ref(props.modelValue);
|
||||
watch(modelValue, (value) => {
|
||||
emit('update:modelValue', value);
|
||||
});
|
||||
</script>
|
|
@ -25,6 +25,7 @@
|
|||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="changePage('/profile')">个人中心</el-dropdown-item>
|
||||
<el-dropdown-item @click="changePage('/class')">班级中心</el-dropdown-item>
|
||||
<el-dropdown-item divided command="logout">
|
||||
<span>退出登录</span>
|
||||
</el-dropdown-item>
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
author: yangws
|
||||
time: 2024-20-24 17:20:50
|
||||
function: 用于删除班级更新主页面
|
||||
*/
|
||||
import { defineStore } from "pinia"
|
||||
|
||||
const delClassDemo = defineStore(
|
||||
'del',
|
||||
{
|
||||
state: () => ({
|
||||
idDelete: false
|
||||
}),
|
||||
actions: {
|
||||
//删除提醒
|
||||
isDelClass(){
|
||||
this.idDelete = true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default delClassDemo
|
|
@ -0,0 +1,53 @@
|
|||
<template>
|
||||
<el-menu
|
||||
style="border:none;overflow: auto;flex: 1"
|
||||
class="el-menu-vertical-demo"
|
||||
:default-active="activeIndex"
|
||||
@select="handleSelect"
|
||||
>
|
||||
<template v-for="(item,index) in classList" :key="index">
|
||||
<el-sub-menu :index="`${index}`">
|
||||
<template #title>
|
||||
<span style="overflow: hidden;white-space: nowrap;text-overflow: ellipsis;">{{item.caption}}</span>
|
||||
</template>
|
||||
<el-menu-item-group>
|
||||
<el-menu-item v-for="(items,routerIndex) in menuItems" :key="`${routerIndex}`" :index="`${items.index}-${item.id}`">{{items.title}}</el-menu-item>
|
||||
</el-menu-item-group>
|
||||
</el-sub-menu>
|
||||
</template>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref,defineProps,defineEmits} from "vue";
|
||||
import { useRouter } from 'vue-router'
|
||||
const activeIndex = ref('0')
|
||||
const router = useRouter()
|
||||
const props = defineProps({
|
||||
classList:{
|
||||
type:Array,
|
||||
},
|
||||
menuItems:{
|
||||
type:Array,
|
||||
}
|
||||
})
|
||||
const emits = defineEmits(['handleSelect'])
|
||||
|
||||
//点击跳转路由
|
||||
const handleSelect = (itemDom,pathKey) => {
|
||||
const parts = pathKey[1].split("-")
|
||||
const result = parts.slice(0, 2).join("-")
|
||||
const index = props.menuItems.findIndex(item=>item.index===result)
|
||||
const id = props.classList[pathKey[0]].id
|
||||
// router.push({
|
||||
// path: `${props.menuItems[index].path}/${id}`,
|
||||
// query: { id }
|
||||
// })
|
||||
emits('handleSelect',{index,id})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,417 @@
|
|||
<template>
|
||||
<el-card style="width: 100%;height: 100%">
|
||||
<template #header>
|
||||
<div class="card-header" style="text-align: left">
|
||||
<el-button type="primary" @click="addGroup">新建分组</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="groupList.length > 0">
|
||||
<div style="font-size: 16px;font-weight: bold;color: #000;text-align: left;margin-bottom: 5px">可用分组</div>
|
||||
<div class="groupList">
|
||||
<template v-for="(item,index) in groupList" :key="index">
|
||||
<el-card style="width: 20%;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
position: relative;"
|
||||
v-if="item.parentid === 0"
|
||||
@mouseenter="cardEnter(item,index)"
|
||||
@mouseleave="cardLeave(item,index)"
|
||||
>
|
||||
<div class="card-content" @click="showGroupDialog(item)">
|
||||
<div style="text-align: left;margin-bottom:10px">
|
||||
<el-text class="mx-1">小组名称:</el-text>
|
||||
<el-text class="mx-1" type="primary" size="large">
|
||||
{{item.groupname}}
|
||||
</el-text>
|
||||
</div>
|
||||
<el-row :gutter="4">
|
||||
<el-col>
|
||||
<el-text class="mx-1" type="warning">共{{item.studentcount}}名学生</el-text>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-popconfirm
|
||||
confirm-button-text="是"
|
||||
title="确定删除该小组吗?"
|
||||
@confirm="delGroup(item,index)"
|
||||
>
|
||||
<template #reference>
|
||||
<div class="card-row" v-show="item.isShow">
|
||||
删除
|
||||
</div>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</el-card>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-empty description="暂无小组" style="margin: 0 auto"/>
|
||||
</template>
|
||||
|
||||
</el-card>
|
||||
<!-- 新建小组-->
|
||||
<el-dialog v-model="groupVisible" title="新建小组" width="40%">
|
||||
<el-form ref="myForm" label-width="80px" :model="groupForm" :rules="rules">
|
||||
<el-form-item label="小组名称" style="width: 80%" prop="groupname">
|
||||
<el-input v-model="groupForm.groupname" placeholder="请输入小组名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" style="width: 80%" prop="orderidx">
|
||||
<el-input-number v-model="groupForm.orderidx" placeholder="排序"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="对应学科">
|
||||
{{ userStore.edusubject }}
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
请首先创建小组,完成后再点击进入添加学生
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="groupVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="btnGroupSave">确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 添加学生-->
|
||||
<el-dialog v-model="dialogVisible" width="60%">
|
||||
<el-form>
|
||||
<el-form-item>
|
||||
<!-- 选择学生-->
|
||||
<div class="allItems">
|
||||
<el-row :gutter="4" style="width: 100%">
|
||||
<el-col :span="4">已选学生:</el-col>
|
||||
<el-col :span="20" class="studentContent">
|
||||
<div class="aItem" @mouseenter="showGroup(stuItem,stuIndex)" @mouseleave="hideGroup(stuItem,stuIndex)" v-for="(stuItem,stuIndex) in selectStudents" :key="stuIndex">
|
||||
<el-tag closable size="large" :class="stuItem.choose?'el-row-group':''" style="width: 100%" plain type="primary" @close="selectStudent(stuItem,stuIndex)">{{stuItem.studentname}}</el-tag>
|
||||
<el-button v-show="stuItem.showGroup" class="itemGroup" plain link type="primary" @click="chooseGroup(stuItem,stuIndex)">{{!stuItem.choose?'设置组长':''}}</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-divider />
|
||||
<el-row :gutter="4" style="width: 100%">
|
||||
<el-col :span="4">未选学生:</el-col>
|
||||
<el-col :span="20" class="studentContent">
|
||||
<div class="aItem" v-for="(stuItem,stuIndex) in avaliableStudents" :key="stuIndex">
|
||||
<el-button style="width: 100%" plain @click="chooseItem(stuItem,stuIndex)">{{stuItem.name || stuItem.studentname}}</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="btnSave">确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {listClassmain, listClassuser, addClassgroup, listClassgroup, delClassgroup,getClassgroup,updateClassgroup} from '@/api/classManage/index'
|
||||
import {ref, onMounted, reactive, defineProps, watch} from 'vue'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import {useRoute} from 'vue-router'
|
||||
import {ElMessage} from "element-plus";
|
||||
|
||||
const userStore = useUserStore()
|
||||
const route = useRoute()
|
||||
const props = defineProps({
|
||||
classId: {type: Number}
|
||||
})
|
||||
//表单验证
|
||||
const groupForm = reactive({
|
||||
groupname: '',
|
||||
orderidx: 0,
|
||||
classid: Number(props.classId),
|
||||
edituserid: userStore.id,
|
||||
edusubject: userStore.edusubject,
|
||||
userid : 0,
|
||||
studentid : 0,
|
||||
parentid:0,
|
||||
status:''
|
||||
})
|
||||
//用于可以分组的学生
|
||||
const avaliableStudents = ref([])
|
||||
const selectStudents = ref([])
|
||||
const rules = reactive({
|
||||
groupname: [
|
||||
{ required: true, message: '请输入小组名称', trigger: 'blur' },
|
||||
{ min: 1, max: 10, message: '小组名称必须是 1-10 位 的字符', trigger: 'blur' }
|
||||
],
|
||||
})
|
||||
const myForm = ref(null)
|
||||
//获取对应的是哪一个班级
|
||||
const routeClass = ref(0)
|
||||
//弹窗控制
|
||||
const dialogVisible = ref(false)
|
||||
const groupVisible = ref(false)
|
||||
//左侧班级控制
|
||||
const classList = ref([])
|
||||
//小组列表
|
||||
const groupList = ref([])
|
||||
//当前小组的信息
|
||||
const groupFormInfo = ref({})
|
||||
//获取parentId
|
||||
const parentId = ref(0)
|
||||
//获取组长的信息
|
||||
const groupLeader = reactive({
|
||||
id: 0,
|
||||
name: '',
|
||||
})
|
||||
// 获取学生信息
|
||||
const getStudentInfo = (id) => {
|
||||
avaliableStudents.value = []
|
||||
listClassuser({ classid:id, pageSize: 100 }).then(response => {
|
||||
response.rows.forEach(item => {
|
||||
item.showGroup = false
|
||||
item.choose = false
|
||||
if(item.inrole == 'student'){
|
||||
const index = groupList.value.findIndex(items => items.studentid == item.studentid)
|
||||
if(index === -1){
|
||||
avaliableStudents.value.push(item)
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 获取班级信息
|
||||
const getClassInfo = () => {
|
||||
listClassmain({ entpid: userStore.deptId, pageSize: 500, status: 'open' }).then(response => {
|
||||
classList.value = response.rows.map(item => {
|
||||
return {
|
||||
...item,
|
||||
}
|
||||
})
|
||||
routeClass.value = classList.value.findIndex(item => item.id == props.classId)
|
||||
});
|
||||
}
|
||||
//选择学生
|
||||
const chooseItem = (item,stuIndex) => {
|
||||
let formdata = {}
|
||||
formdata.classid = props.classId;
|
||||
formdata.edituserid = userStore.id;
|
||||
formdata.userid = item.userid;
|
||||
formdata.parentid = parentId.value;
|
||||
formdata.studentid = item.studentid;
|
||||
addClassgroup(formdata).then(response => {
|
||||
if(response.code === 200)
|
||||
//刷新小组
|
||||
getGroupListInfo()
|
||||
//刷新已选学生列表
|
||||
getSelectStudentInfo(parentId.value)
|
||||
})
|
||||
avaliableStudents.value.splice(stuIndex,1)
|
||||
}
|
||||
//已选择的学生
|
||||
const selectStudent = (item) => {
|
||||
delClassgroup(item.id).then(() => {
|
||||
getSelectStudentInfo(parentId.value)
|
||||
getGroupListInfo()
|
||||
})
|
||||
avaliableStudents.value.push(item)
|
||||
}
|
||||
//选择组长
|
||||
const chooseGroup = (item) => {
|
||||
let choose = item.choose
|
||||
selectStudents.value.forEach((items) => {
|
||||
items.showGroup = false
|
||||
items.choose = false
|
||||
})
|
||||
const index = selectStudents.value.findIndex(items => items.studentid == item.studentid)
|
||||
selectStudents.value[index].choose = !choose
|
||||
item.showGroup = true
|
||||
updateClassgroup({ id: groupFormInfo.value.id, studentid: item.studentid }).then(() => {
|
||||
getClassgroup(groupFormInfo.value.id).then(res => {
|
||||
groupLeader.id = res.data.studentid;
|
||||
groupLeader.name = res.data.studentname;
|
||||
})
|
||||
});
|
||||
}
|
||||
/*
|
||||
author: yangws
|
||||
time: 2024-20-23 11:20:04
|
||||
function:鼠标的移入移出
|
||||
*/
|
||||
const showGroup = (item) => {
|
||||
item.showGroup = true
|
||||
}
|
||||
const hideGroup = (item) => {
|
||||
if(item.choose) return
|
||||
item.showGroup = false
|
||||
}
|
||||
const showGroupDialog = (item) => {
|
||||
parentId.value = item.id
|
||||
// 获取点击小组的信息
|
||||
getClassgroup(item.id).then((response) => {
|
||||
groupFormInfo.value = Object.assign({},response.data)
|
||||
//未选学生列表
|
||||
getStudentInfo(props.classId)
|
||||
//已选学生列表
|
||||
getSelectStudentInfo(parentId.value)
|
||||
//获取小组列表
|
||||
getGroupListInfo()
|
||||
dialogVisible.value = true
|
||||
})
|
||||
}
|
||||
const btnSave = () => {
|
||||
updateClassgroup({id:groupFormInfo.value.id,groupname:groupFormInfo.value.groupname,orderidx:groupFormInfo.value.orderidx}).then((response) => {
|
||||
if (response.code === 200) {
|
||||
ElMessage({
|
||||
message: '修改成功',
|
||||
type: 'success',
|
||||
})
|
||||
dialogVisible.value = false
|
||||
getGroupListInfo()
|
||||
}
|
||||
})
|
||||
}
|
||||
//新建小组
|
||||
const addGroup = () => {
|
||||
groupVisible.value = true
|
||||
}
|
||||
const btnGroupSave = () => {
|
||||
myForm.value.validate((valid) => {
|
||||
if (valid) {
|
||||
addClassgroup(groupForm).then((response) => {
|
||||
if (response.code === 200) {
|
||||
ElMessage({
|
||||
message: '新增成功',
|
||||
type: 'success',
|
||||
})
|
||||
getGroupListInfo()
|
||||
}
|
||||
})
|
||||
groupVisible.value = false
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
//获取小组列表
|
||||
const getGroupListInfo = () => {
|
||||
//获取小组列表
|
||||
listClassgroup({ classid: props.classId, orderby: 'orderidx', pageSize: 100 }).then(response => {
|
||||
groupList.value = response.rows.map(item => {
|
||||
return {
|
||||
...item,
|
||||
isShow : false
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
//获取已选小组学生
|
||||
const getSelectStudentInfo = (id) => {
|
||||
listClassgroup({ parentid: id, orderby: 'orderidx', pageSize: 100 }).then(response => {
|
||||
selectStudents.value = response.rows.map(item => {
|
||||
item.showGroup=false
|
||||
item.choose=false
|
||||
return {
|
||||
...item
|
||||
}
|
||||
})
|
||||
//获取小组长
|
||||
changeGroupLeader()
|
||||
})
|
||||
}
|
||||
//进入小组卡片和离开小组卡片
|
||||
const cardEnter = (item) => {
|
||||
item.isShow = true
|
||||
}
|
||||
const cardLeave = (item) => {
|
||||
item.isShow = false
|
||||
}
|
||||
//删除小组
|
||||
const delGroup = (item) => {
|
||||
delClassgroup(item.id).then((response) => {
|
||||
if (response.code === 200) {
|
||||
ElMessage({
|
||||
message: '删除成功',
|
||||
type: 'success',
|
||||
})
|
||||
getGroupListInfo()
|
||||
}
|
||||
})
|
||||
}
|
||||
//改变小组长
|
||||
const changeGroupLeader = () => {
|
||||
const index = selectStudents.value.findIndex(item => groupFormInfo.value.studentid == item.studentid)
|
||||
selectStudents.value.forEach(item => {
|
||||
item.choose = false
|
||||
})
|
||||
if(index !== -1)
|
||||
selectStudents.value[index].choose = true
|
||||
}
|
||||
onMounted(() => {
|
||||
getClassInfo()
|
||||
getStudentInfo(props.classId)
|
||||
getGroupListInfo()
|
||||
})
|
||||
watch(()=> props.classId,()=> {
|
||||
getClassInfo()
|
||||
getStudentInfo(props.classId)
|
||||
getGroupListInfo()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.allItems{
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
flex-wrap: wrap;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
}
|
||||
.allItems .aItem{
|
||||
margin-bottom: 20px;
|
||||
margin-right: 5px;
|
||||
position: relative;
|
||||
width: 80px;
|
||||
}
|
||||
.allItems .aItem .itemGroup{
|
||||
position: absolute;
|
||||
top: 32px;
|
||||
left: 10px;
|
||||
}
|
||||
.el-row-group::after {
|
||||
content: "组";
|
||||
font-size: 12px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
color: rgb(121,187,255);
|
||||
transform: rotate(45deg);
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
font-weight: bold;
|
||||
letter-spacing:2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.groupList{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.card-row {
|
||||
font-size: 12px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
color: rgb(121,187,255);
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
font-weight: bold;
|
||||
letter-spacing:2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.studentContent{
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
flex-wrap: wrap;
|
||||
max-height: 150px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.card-content{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,80 @@
|
|||
<template>
|
||||
<el-card style="width: 100%">
|
||||
<template #header>
|
||||
<div style="text-align: left">
|
||||
<el-button type="danger" @click="deleteClassRoom">删除班级</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-descriptions :column="1">
|
||||
<el-descriptions-item label="班级名称">{{ classInfo.className }}</el-descriptions-item>
|
||||
<el-descriptions-item label="教师">
|
||||
<template v-if="classInfo.teacher.length > 0">
|
||||
<el-tag type="primary" v-for="(item, index) in classInfo.teacher" :key="index">{{item.name}}</el-tag>
|
||||
</template>
|
||||
<template v-else>暂无</template>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="学生人数">{{ classInfo.student.length }}人</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ElMessage, ElMessageBox} from "element-plus";
|
||||
import { getClassmain,listClassuser,leaveClass} from '@/api/classManage/index'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import {reactive,onMounted,defineProps,nextTick,watch} from 'vue'
|
||||
import delClassDemo from '@/store/modules/delClass'
|
||||
const props = defineProps({
|
||||
classId: {
|
||||
type: Number,
|
||||
}
|
||||
})
|
||||
const classInfo = reactive({
|
||||
className: '',
|
||||
teacher: [],
|
||||
student: []
|
||||
})
|
||||
const isDelClass = delClassDemo()
|
||||
const userStore = useUserStore()
|
||||
//删除教室
|
||||
const deleteClassRoom = () => {
|
||||
ElMessageBox.alert('确认删除该班级?', {
|
||||
confirmButtonText: '确认',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
leaveClass({ classid: props.classId, userid: userStore.id, inrole: 'teacher' }).then(() => {
|
||||
ElMessage({
|
||||
message: '删除成功',
|
||||
type: 'success',
|
||||
})
|
||||
//用于更新班级列表
|
||||
isDelClass.isDelClass()
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
});
|
||||
})
|
||||
}
|
||||
const getClassInfo = () => {
|
||||
if(props.classId){
|
||||
getClassmain(props.classId).then(response => {
|
||||
classInfo.className = response.data.caption
|
||||
listClassuser({classid:props.classId,pageSize:100}).then(res => {
|
||||
classInfo.teacher = res.rows.filter(item => item.inrole === 'teacher')
|
||||
classInfo.student = res.rows.filter(item => item.inrole === 'student')
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
getClassInfo()
|
||||
})
|
||||
})
|
||||
watch(()=> props.classId,()=> {
|
||||
getClassInfo()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,292 @@
|
|||
<template>
|
||||
<div class="common-layout">
|
||||
<el-container>
|
||||
<el-aside style="width: 200px;margin-top: 20px">
|
||||
<el-card style="width: 200px" class="el-card-demo" :style="{'min-height': (viewportHeight - 120) + 'px'}">
|
||||
<div :style="{'max-height': (viewportHeight - 120) + 'px','overflow-y': 'auto'}">
|
||||
<Aside :menuItems="menuItems" :classList="classList" @handleSelect="handleSelect"></Aside>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div>
|
||||
<el-button @click="addClass" type="primary" :icon="Plus" >新增班级</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-card>
|
||||
</el-aside>
|
||||
<el-main :style="{'min-height': (viewportHeight - 160) + 'px'}">
|
||||
<!-- <router-view :style="{'height': (viewportHeight - 120) + 'px','overflow-y': 'auto'}" :key="route.path"></router-view>-->
|
||||
<!-- 班级概况-->
|
||||
<ClassInfo v-if="currentIndex==0" :classId="classId"></ClassInfo>
|
||||
<!-- 学生列表-->
|
||||
<StudentList v-else-if="currentIndex==1" :classId="classId"></StudentList>
|
||||
<!-- 分组情况-->
|
||||
<BasicGroup v-else-if="currentIndex==2" :classId="classId"></BasicGroup>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</div>
|
||||
<el-dialog v-model="dialogVisible" title="新增班级" width="50%">
|
||||
<el-form
|
||||
style="width: 100%"
|
||||
label-width="auto"
|
||||
:model="classForm"
|
||||
:rules="rules"
|
||||
ref="myForm"
|
||||
>
|
||||
<el-form-item label="班级名称" style="margin-right: 10px;width: 50%" prop="caption">
|
||||
<el-input v-model="classForm.caption" placeholder="请输入班级名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="任选学科" style="margin-right: 10px;">
|
||||
<el-radio-group v-model="classForm.edusubject" class="ml-4">
|
||||
<template v-for="(item, index) in courseList" :key="index">
|
||||
<el-radio v-if="item.edustage == userStore.edustage" :value="item.itemtitle">{{ item.itemtitle }}</el-radio>
|
||||
</template>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="年级" style="margin-right: 10px;" prop="agekey">
|
||||
<el-radio-group v-model="classForm.edudegree">
|
||||
<template v-for="(item,index) in gradeList" :key="index">
|
||||
<el-radio v-if="item.edustage == userStore.edustage" :value="item.value">{{ item.label }}</el-radio>
|
||||
</template>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="老师" prop="teacherid">
|
||||
{{ userStore.nickName }}
|
||||
</el-form-item>
|
||||
<el-form-item label="简要说明" style="margin-right: 10px;" prop="classdesc">
|
||||
<el-input v-model="classForm.classdesc" placeholder="请输入简要说明"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="btnSave">确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref, onMounted, reactive,watch,nextTick} from 'vue'
|
||||
import {listClassmain, addClassmain, listEvaluation} from '@/api/classManage/index'
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import {ElMessage} from "element-plus";
|
||||
import delClassDemo from '@/store/modules/delClass'
|
||||
import StudentList from './studentList.vue'
|
||||
import BasicGroup from './basicGroup.vue'
|
||||
import ClassInfo from './classInfo.vue'
|
||||
import Aside from './aside.vue'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const isDel = delClassDemo()
|
||||
//获取班级信息
|
||||
const classList = ref([])
|
||||
const menuItems = [
|
||||
{
|
||||
index: '1-1',
|
||||
title: '班级概况',
|
||||
path: '/classInfo'
|
||||
},
|
||||
{
|
||||
index: '1-2',
|
||||
title: '学生名单',
|
||||
path: '/studentList'
|
||||
|
||||
},
|
||||
{
|
||||
index: '1-3',
|
||||
title: '基本分组',
|
||||
path: '/basicGroup'
|
||||
},
|
||||
]
|
||||
//创建班级基本信息
|
||||
const classForm = reactive({
|
||||
caption: '',
|
||||
classdesc: '',
|
||||
teacherid: '',
|
||||
agekey:'',
|
||||
edusubject:'',
|
||||
edudegree:''
|
||||
})
|
||||
const viewportHeight = ref(0)
|
||||
//学科列表
|
||||
const courseList = ref([])
|
||||
//班级id
|
||||
const classId = ref('')
|
||||
//当前页面
|
||||
const currentIndex = ref(0)
|
||||
//年级
|
||||
const gradeList = ref([
|
||||
{ label: '一年级', value: '1年级', checked: false, edustage: '小学', agekey: 1 },
|
||||
{ label: '二年级', value: '2年级', checked: false, edustage: '小学', agekey: 2 },
|
||||
{ label: '三年级', value: '3年级', checked: false, edustage: '小学', agekey: 3 },
|
||||
{ label: '四年级', value: '4年级', checked: false, edustage: '小学', agekey: 4 },
|
||||
{ label: '五年级', value: '5年级', checked: false, edustage: '小学', agekey: 5},
|
||||
{ label: '六年级', value: '6年级', checked: false, edustage: '小学', agekey: 6 },
|
||||
{ label: '初一', value: '初一', checked: false, edustage: '初中', agekey: 7 },
|
||||
{ label: '初二', value: '初二', checked: false, edustage: '初中', agekey: 8 },
|
||||
{ label: '初三', value: '初三', checked: false, edustage: '初中', agekey: 9 },
|
||||
{ label: '高一', value: '高一', checked: false, edustage: '高中', agekey: 10 },
|
||||
{ label: '高二', value: '高二', checked: false, edustage: '高中', agekey: 11 },
|
||||
{ label: '高三', value: '高三', checked: false, edustage: '高中', agekey: 12 },
|
||||
])
|
||||
//打开班级
|
||||
const dialogVisible = ref(false)
|
||||
//校验表单
|
||||
const myForm = ref(null)
|
||||
const rules = reactive({
|
||||
caption: [
|
||||
{ required: true, message: '请输入班级名称', trigger: 'blur' },
|
||||
{ min: 1, max: 10, message: '班级名称必须是 1-10 位 的字符', trigger: 'blur' }
|
||||
],
|
||||
})
|
||||
|
||||
// 获取班级信息
|
||||
const getClassInfo = () => {
|
||||
classList.value = []
|
||||
listClassmain({ entpid: userStore.deptId, pageSize: 500, status: 'open' }).then(response => {
|
||||
response.rows.forEach(item => {
|
||||
if(item.classteacherids && Number(item.classteacherids) === userStore?.id){
|
||||
classList.value.push(item)
|
||||
}
|
||||
})
|
||||
if(classList.value.length > 0){
|
||||
classId.value = classList.value[0].id
|
||||
currentIndex.value = 0
|
||||
}
|
||||
});
|
||||
}
|
||||
//获取所有学科
|
||||
const getCourseList = () => {
|
||||
// 获取基础的学科
|
||||
listEvaluation({ itemkey: "subject", pageSize: 500 }).then((res) => {
|
||||
courseList.value = [...res.rows];
|
||||
});
|
||||
}
|
||||
// 新增班级
|
||||
const addClass = () => {
|
||||
dialogVisible.value = true
|
||||
getCourseList()
|
||||
}
|
||||
const btnSave = () => {
|
||||
myForm.value.validate((valid) => {
|
||||
if (valid) {
|
||||
//查看班级是否重名
|
||||
listClassmain({ entpid: userStore.deptId, status: 'open', pageSize: 500 }).then(response => {
|
||||
const data = [...response.rows]
|
||||
const existList = [];
|
||||
data.forEach(item => {
|
||||
if (parseInt(textSimilar(item.caption, classForm.caption, 2)) > 80) {
|
||||
existList.push(item);
|
||||
}
|
||||
})
|
||||
|
||||
if (existList.length == 0) {
|
||||
const age = classForm.edudegree;
|
||||
const index = gradeList.value.findIndex(item => item.label === age);
|
||||
classForm.agekey = gradeList.value[index].agekey
|
||||
classForm.edudegree = `${gradeList.value[index].agekey}年级`
|
||||
classForm.entpid = userStore.deptId;
|
||||
classForm.status = 'open';
|
||||
classForm.teachername = userStore.nickName;
|
||||
classForm.teacherid = userStore.id;
|
||||
classForm.teacherSubject = classForm.edusubject;
|
||||
addClassmain(classForm).then(response => {
|
||||
if (response.code === 200) {
|
||||
dialogVisible.value = false
|
||||
ElMessage({
|
||||
message: '新增成功',
|
||||
type: 'success',
|
||||
})
|
||||
getClassInfo()
|
||||
}
|
||||
});
|
||||
}else{
|
||||
ElMessage({
|
||||
message: '班级名称重复',
|
||||
type: 'warning',
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
//文本计算
|
||||
const textSimilar = (s, t, f) => {
|
||||
if (!s || !t) {
|
||||
return 0
|
||||
}
|
||||
if (s === t) {
|
||||
return 100;
|
||||
}
|
||||
var l = s.length > t.length ? s.length : t.length
|
||||
var n = s.length
|
||||
var m = t.length
|
||||
var d = []
|
||||
f = f || 2
|
||||
var min = function (a, b, c) {
|
||||
return a < b ? (a < c ? a : c) : (b < c ? b : c)
|
||||
}
|
||||
var i, j, si, tj, cost
|
||||
if (n === 0) return m
|
||||
if (m === 0) return n
|
||||
for (i = 0; i <= n; i++) {
|
||||
d[i] = []
|
||||
d[i][0] = i
|
||||
}
|
||||
for (j = 0; j <= m; j++) {
|
||||
d[0][j] = j
|
||||
}
|
||||
for (i = 1; i <= n; i++) {
|
||||
si = s.charAt(i - 1)
|
||||
for (j = 1; j <= m; j++) {
|
||||
tj = t.charAt(j - 1)
|
||||
if (si === tj) {
|
||||
cost = 0
|
||||
} else {
|
||||
cost = 1
|
||||
}
|
||||
d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost)
|
||||
}
|
||||
}
|
||||
let res = (1 - d[n][m] / l) * 100
|
||||
return res.toFixed(f)
|
||||
}
|
||||
//获取视口高度
|
||||
const getViewportHeight = () => {
|
||||
return Math.max(
|
||||
document.documentElement.clientHeight,
|
||||
window.innerHeight || 0
|
||||
);
|
||||
}
|
||||
const handleSelect = (obj) => {
|
||||
classId.value = obj.id
|
||||
currentIndex.value = obj.index
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getClassInfo()
|
||||
nextTick(() => {
|
||||
viewportHeight.value = getViewportHeight()
|
||||
})
|
||||
window.addEventListener('resize', () => {
|
||||
viewportHeight.value = getViewportHeight()
|
||||
})
|
||||
|
||||
})
|
||||
watch(() => isDel.idDelete, () => {
|
||||
//判断是否更改了班级
|
||||
getClassInfo()
|
||||
isDel.idDelete = false
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-card-demo{
|
||||
width: 200px;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,454 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-card style="width: 100%;height: 100%">
|
||||
<template #header>
|
||||
<div style="text-align: left;display: flex;justify-content: space-between">
|
||||
<div>
|
||||
<el-button type="primary" @click="addStudent(0)">新增学生</el-button>
|
||||
<el-button type="primary" @click="importStudent()">导入学生</el-button>
|
||||
</div>
|
||||
<el-text class="mx-1">点击学生头像查看学生信息</el-text>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<div class="studentContent">
|
||||
<template v-if="studentList.length > 0">
|
||||
<div v-for="(item,index) in studentList" :key="index" style="width: 10%" @click="addStudent(item.studentid)">
|
||||
<div>
|
||||
<el-avatar
|
||||
src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"
|
||||
/>
|
||||
</div>
|
||||
<div>{{ item.name }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-empty description="暂无学生" style="margin: 0 auto"/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 新增学生-->
|
||||
<el-dialog v-model="studentVisible" title="学生信息" width="60%" append-to-body>
|
||||
<el-form label-width="80px" ref="myForm" :model="studentForm" :rules="rules">
|
||||
<el-form-item label="学生姓名" prop="name">
|
||||
<el-input v-model="studentForm.name" placeholder="请输入学生姓名" style="width: 50%"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="studentForm.gender">
|
||||
<el-radio value="">空缺</el-radio>
|
||||
<el-radio value="男">男生</el-radio>
|
||||
<el-radio value="女">女生</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="出生日期" prop="birthday">
|
||||
<el-date-picker v-model="studentForm.birthday" placeholder="请选择出生日期" style="width: 50%"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="住址" prop="address">
|
||||
<el-input v-model="studentForm.address" placeholder="请输入住址" style="width: 50%"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="联系人" prop="parentmobile">
|
||||
<el-input v-model="studentForm.parentname" placeholder="请输入联系人" style="width: 50%"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="电话" prop="parentmobile">
|
||||
<el-input v-model="studentForm.parentmobile" placeholder="请输入电话" style="width: 50%"/>
|
||||
</el-form-item>
|
||||
<div>
|
||||
<el-row :gutter="4">
|
||||
<el-col :span="12">
|
||||
<el-form-item label-width="100px" label="平台登录账号">
|
||||
系统自动创建
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label-width="100px" label="平台登录密码">
|
||||
系统自动创建,默认为123123
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button type="warning" v-show="studentForm.id > 0" @click="delStudent(1)">移出班级</el-button>
|
||||
<el-button type="danger" v-show="studentForm.id > 0 && studentForm.editoruserid == userStore.id" @click="delStudent(2)">删除学生</el-button>
|
||||
<el-button @click="studentVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="btnStudentSave">确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 学生导入-->
|
||||
<el-dialog title="学生导入" v-model="importVisiable" :width="600" append-to-body>
|
||||
<el-form>
|
||||
<el-form-item label="第一步">
|
||||
<el-link type="primary" :underline="true" style="font-size: 1.2em"
|
||||
@click="downloadTemplate(tableInfo)">下载学生名单的Excel模板</el-link>
|
||||
</el-form-item>
|
||||
<el-form-item label="第二步">
|
||||
<div>打开下载到本地的Excel,填写学生的姓名等数据。</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="第三步">
|
||||
<div>
|
||||
<el-upload :on-change="handleStudentFileUploadChange"
|
||||
ref="uploadRef" :limit="1" accept=".xlsx, .xls" :auto-upload="false" drag>
|
||||
<div class="el-upload__text">将Excel文件拖到此处,或<em>点击上传</em></div>
|
||||
</el-upload>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="导入学生" v-if="tableInfo.studentList.length > 0">
|
||||
<template v-for="(item, index) in tableInfo.studentList" :key="index">
|
||||
<el-tag size="large" style="margin: 5px" closable @close="handleRemoveImportStudent(index)">{{ item.name }}</el-tag>
|
||||
</template>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="importVisiable = false">关 闭</el-button>
|
||||
<el-button type="primary" @click="HandleImportStudentData()">导入</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {addStudentmain, listClassuser,updateStudentmain,getClassmain,getStudentmain,leaveClass,removeStudentDataAll,addStudentmainByNameArray} from '@/api/classManage/index'
|
||||
import {ref, onMounted, reactive, nextTick, defineProps, watch} from 'vue'
|
||||
import {ElMessage,ElMessageBox} from "element-plus";
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import * as XLSX from 'xlsx'
|
||||
|
||||
const studentVisible = ref(false)
|
||||
const importVisiable = ref(false)
|
||||
const userStore = useUserStore()
|
||||
const props = defineProps({
|
||||
classId: {type: Number}
|
||||
})
|
||||
//学生和老师的列表
|
||||
const studentList = ref([])
|
||||
let studentForm = reactive({
|
||||
name: '',
|
||||
gender: '',
|
||||
birthday: '',
|
||||
address: '',
|
||||
parentname: '',
|
||||
parentmobile: '',
|
||||
isAutoCreateTimAccount: false,
|
||||
})
|
||||
// 用户导入
|
||||
const tableInfo = reactive({
|
||||
//在这配置excel表格
|
||||
columns: [
|
||||
{ title: '姓名', key: 'name' },
|
||||
{ title: '性别', key: 'gender' },
|
||||
{ title: '手机号', key: 'phone' },
|
||||
{ title: '父母手机号1', key: 'parentmobile' },
|
||||
{ title: '父母手机号2', key: 'parentmobile2' },
|
||||
{ title: '年级', key: 'classname' },
|
||||
{ title: '地址', key: 'address' },
|
||||
{ title: '生日', key: 'birthday' },
|
||||
{ title: '学校名称', key: 'schoolname' },
|
||||
{ title: '描述', key: 'status' },
|
||||
],
|
||||
studentList: [],
|
||||
})
|
||||
//班级详情
|
||||
const classInfo = reactive({})
|
||||
//验证新增学生必填
|
||||
const myForm = ref(null)
|
||||
const rules = reactive({
|
||||
name: [
|
||||
{ required: true, message: '请输入学生名称', trigger: 'blur' },
|
||||
{ min: 2, max: 5, message: '学生必须是 2-5 位 的字符', trigger: 'blur' }
|
||||
],
|
||||
birthday: [
|
||||
{ required: true, message: '请选择出生日期', trigger: 'blur' }
|
||||
]
|
||||
})
|
||||
|
||||
// 获取班级学生信息
|
||||
const getClassStudentInfo = () => {
|
||||
studentList.value = []
|
||||
listClassuser({ classid:props.classId, pageSize: 100 }).then(response => {
|
||||
response.rows.forEach(item => {
|
||||
if(item.inrole == 'student'){
|
||||
studentList.value.push(item)
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
//获取班级信息
|
||||
const getClassInfo = () => {
|
||||
getClassmain(props.classId).then(response => {
|
||||
classInfo.value = Object.assign({},response.data )
|
||||
})
|
||||
}
|
||||
const btnStudentSave = () => {
|
||||
myForm.value.validate((valid) => {
|
||||
if (valid) {
|
||||
//判断学生是否存在
|
||||
if(studentForm.id > 0){
|
||||
updateStudentmain(studentForm).then(() => {
|
||||
ElMessage({
|
||||
message: '修改成功',
|
||||
type: 'success',
|
||||
})
|
||||
})
|
||||
}else{
|
||||
studentForm.entpid = classInfo.value.entpid;
|
||||
studentForm.classid = classInfo.value.id;
|
||||
studentForm.classname = classInfo.value.caption;
|
||||
studentForm.schoolname = classInfo.value.entpname;
|
||||
studentForm.status = '';
|
||||
studentForm.editoruserid = userStore.id;
|
||||
addStudentmain(studentForm).then((response) => {
|
||||
if (response.code === 200) {
|
||||
ElMessage({
|
||||
message: '新增成功',
|
||||
type: 'success',
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
getClassStudentInfo()
|
||||
studentVisible.value = false
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
//新增学生
|
||||
const addStudent = (id) => {
|
||||
if(id === 0){
|
||||
studentForm.id = 0
|
||||
studentForm.entpid = 0
|
||||
studentForm.name = ''
|
||||
studentVisible.value = true
|
||||
}else{
|
||||
getStudentmain(id).then((response) => {
|
||||
nextTick(() => {
|
||||
studentForm.address = response.data.address
|
||||
studentForm.name = response.data.name
|
||||
studentForm.birthday = response.data.birthday
|
||||
studentForm.gender = response.data.gender
|
||||
studentForm.parentname = response.data.parentname
|
||||
studentForm.parentmobile = response.data.parentmobile
|
||||
studentForm.id = response.data.id
|
||||
studentVisible.value = true
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
//删除学生
|
||||
const delStudent = (index) => {
|
||||
//index 1 移出班级 2 删除学生
|
||||
if(index === 1){
|
||||
ElMessageBox.alert('是否将该学生移出班级', {
|
||||
confirmButtonText: '确认',
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
leaveClass({ classid: props.classId, studentid: studentForm.id, inrole: 'student' }).then((response) => {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '移出成功',
|
||||
})
|
||||
getClassStudentInfo()
|
||||
studentVisible.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
else{
|
||||
ElMessageBox.alert('确认删除该学生并删除该学生所有数据', {
|
||||
confirmButtonText: '确认',
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
leaveClass({classid: props.classId, studentid: studentForm.id, inrole: 'student'}).then((response) => {
|
||||
if (response.code === 200) {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '删除成功',
|
||||
})
|
||||
}
|
||||
removeStudentDataAll(studentForm.id).then((res) => {
|
||||
if (res.code === 200) {
|
||||
getClassStudentInfo()
|
||||
studentVisible.value = false
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
//导入学生
|
||||
const importStudent = () => {
|
||||
importVisiable.value = true
|
||||
}
|
||||
//下载导入模板
|
||||
const downloadTemplate = (tableInfo) => {
|
||||
let expData = [];
|
||||
tableInfo.importColumns = appendTableImportColumns(tableInfo.columns);
|
||||
var header = [];
|
||||
tableInfo.importColumns.map((item, index) => {
|
||||
header[index] = item.title;
|
||||
});
|
||||
//1. 新建一个工作簿
|
||||
let workbook = XLSX.utils.book_new();
|
||||
//2.2 把json对象转成工作表
|
||||
let sheet1 = XLSX.utils.json_to_sheet(expData, { header: header });
|
||||
//3.在工作簿中添加工作表
|
||||
XLSX.utils.book_append_sheet(workbook, sheet1, '导入模板'); //工作簿名称
|
||||
XLSX.writeFile(workbook, '学生名单导入模板.xlsx'); // 保存的文件名
|
||||
}
|
||||
//获取导入表格的列
|
||||
const appendTableImportColumns = (columns) => {
|
||||
return columns.filter((item) => {
|
||||
if (item.hasOwnProperty("title")) {
|
||||
if (item.hasOwnProperty("key")) {
|
||||
return true;
|
||||
} else {
|
||||
if (item.hasOwnProperty("slot") && item.slot.split(".").length > 1) {
|
||||
item.title = item.slot.split(".")[1];
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
//文件上传
|
||||
const handleStudentFileUploadChange = (file) => {
|
||||
let fileTemp = file.raw;
|
||||
if (fileTemp) {
|
||||
if ((fileTemp.type == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
|
||||
|| (fileTemp.type == 'application/vnd.ms-excel')) {
|
||||
handleStudentExcel(fileTemp);
|
||||
} else {
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: '文件格式错误,请删除后重新上传!'
|
||||
})
|
||||
}
|
||||
} else {
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: '请上文件!'
|
||||
})
|
||||
}
|
||||
}
|
||||
const handleStudentExcel = (fileTemp) => {
|
||||
const file = fileTemp;
|
||||
var rABS = false; //是否将文件读取为二进制字符串
|
||||
var f = file;
|
||||
var reader = new FileReader();
|
||||
FileReader.prototype.readAsBinaryString = function (f) {
|
||||
var binary = "";
|
||||
var rABS = false; //是否将文件读取为二进制字符串
|
||||
var wb; //读取完成的数据
|
||||
var outdata;
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
var bytes = new Uint8Array(reader.result);
|
||||
var length = bytes.byteLength;
|
||||
for (var i = 0; i < length; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
if (rABS) {
|
||||
wb = XLSX.read(btoa(fixdata(binary)), {
|
||||
//手动转化
|
||||
type: "base64"
|
||||
});
|
||||
} else {
|
||||
wb = XLSX.read(binary, {
|
||||
type: "binary"
|
||||
});
|
||||
}
|
||||
outdata = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); //outdata就是你想要的东西
|
||||
const tempColumnMapping = {};
|
||||
for (const column of tableInfo.columns) {
|
||||
tempColumnMapping[column.title] = column.key;
|
||||
}
|
||||
const mappedOutdata = outdata.map((item) => {
|
||||
return Object.keys(item).reduce((mappedItem, key) => {
|
||||
const targetKey = tempColumnMapping[key] || key;
|
||||
mappedItem[targetKey] = item[key];
|
||||
return mappedItem;
|
||||
}, {});
|
||||
});
|
||||
tableInfo.studentList = [...mappedOutdata];
|
||||
|
||||
//此处可对数据进行处理
|
||||
let arr = [];
|
||||
outdata.map(v => {
|
||||
let obj = {}
|
||||
obj.code = v['code']
|
||||
obj.name = v['name']
|
||||
obj.pro = v['province']
|
||||
obj.cit = v['city']
|
||||
obj.dis = v['district']
|
||||
arr.push(obj)
|
||||
});
|
||||
// _this.da = arr;
|
||||
// _this.dalen = arr.length;
|
||||
return arr;
|
||||
};
|
||||
reader.readAsArrayBuffer(f);
|
||||
};
|
||||
if (rABS) {
|
||||
reader.readAsArrayBuffer(f);
|
||||
} else {
|
||||
reader.readAsBinaryString(f);
|
||||
}
|
||||
}
|
||||
//点击导入确认
|
||||
const HandleImportStudentData = () => {
|
||||
if(tableInfo.studentList.length == 0){
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: '请选择导入的文件!'
|
||||
})
|
||||
return false
|
||||
}
|
||||
var names = [];
|
||||
tableInfo.studentList.forEach(item => {
|
||||
names.push(item.name);
|
||||
})
|
||||
var formdata = {};
|
||||
formdata.namearray = names.join(",");
|
||||
formdata.entpid = classInfo.value.entpid;
|
||||
formdata.classid = classInfo.value.id;
|
||||
formdata.classname = classInfo.value.caption;
|
||||
formdata.schoolname = classInfo.value.entpname;
|
||||
formdata.status = '';
|
||||
formdata.editoruserid = userStore.id;
|
||||
|
||||
addStudentmainByNameArray(formdata).then(res => {
|
||||
if(res.code == 200){
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '导入成功',
|
||||
})
|
||||
getClassStudentInfo()
|
||||
importVisiable.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
const handleRemoveImportStudent = (index) => {
|
||||
tableInfo.studentList.splice(index, 1);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
studentList.value = []
|
||||
getClassStudentInfo()
|
||||
getClassInfo()
|
||||
})
|
||||
watch(()=> props.classId,()=> {
|
||||
getClassStudentInfo()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.studentContent{
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue