feat: align teacher management UI

fix/non-blocking-route-navigation
chenyuan 4 months ago
parent ac4e101358
commit 373d74e329

@ -300,6 +300,9 @@ export function updateMajor(data) {
url: "/api/user/updateSchoolMajor",
method: "POST",
data,
params: {
userId: data.userId,
},
});
}
// 专业管理-专业删除
@ -383,6 +386,9 @@ export function updateTeacher(data) {
url: "/api/user/updateTeacher",
method: "POST",
data,
params: {
operatorId: data.operatorId,
},
});
}
// 教师管理-删除
@ -570,3 +576,21 @@ export function initClass(params) {
params,
});
}
// 教学班-全班实训数据初始化
export function initializeTeachingClassTrainingData(params) {
return request({
url: "/api/user/initializeTeachingClassTrainingData",
method: "POST",
params,
});
}
// 教学班-单个学生实训数据初始化
export function initializeTeachingClassStudentTrainingData(params) {
return request({
url: "/api/user/initializeTeachingClassStudentTrainingData",
method: "POST",
params,
});
}

@ -7,7 +7,7 @@
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<section :class="[role == 4 ? 'app-main' : 'app-main2']">
<section :class="mainClass">
<router-view v-slot="{ Component, route }">
<transition name="fade-transform" mode="out-in" :key="route.path">
<keep-alive :include="tagsViewStore.cachedViews">
@ -31,6 +31,11 @@ const tagsViewStore = useTagsViewStore();
const route = useRoute();
const router = useRouter();
const role = ref(JSON.parse(getUserInfo()).roleId);
const mainClass = computed(() => {
if (Number(role.value) === 4) return "app-main";
if (Number(role.value) === 3) return "teacher-main";
return "app-main2";
});
const module = ["市场需求挖掘", "产品规划", "产品投放测试", "供应渠道管理", "产品评估与考核"];
// 全局监听路由进入和离开
onBeforeRouteUpdate((to, from) => {
@ -137,6 +142,17 @@ router.beforeEach((to, from, next) => {
background: url("@/assets/images/背景f6.png") no-repeat;
background-size: 100% 100%;
}
.teacher-main {
min-height: calc(100vh - 50px);
width: 100%;
position: relative;
overflow: auto;
padding: 22px 24px 28px;
background:
radial-gradient(circle at 12% 18%, rgba(14, 74, 112, 0.5), transparent 34%),
radial-gradient(circle at 78% 6%, rgba(25, 92, 170, 0.34), transparent 28%),
linear-gradient(135deg, #03070e 0%, #061827 48%, #02060d 100%);
}
.fixed-header + .app-main {
padding-top: 50px;
}
@ -171,4 +187,200 @@ router.beforeEach((to, from, next) => {
background-color: #c0c0c0;
border-radius: 3px;
}
.teacher-main {
color: #e8f5ff;
.app-container {
min-height: calc(100vh - 96px);
padding: 18px 20px 22px;
border: 1px solid rgba(39, 172, 238, 0.28);
border-radius: 14px;
background: linear-gradient(135deg, rgba(6, 23, 36, 0.84), rgba(4, 12, 23, 0.78));
box-shadow: 0 18px 48px rgba(0, 5, 16, 0.34), inset 0 1px 0 rgba(153, 220, 255, 0.08);
backdrop-filter: blur(12px);
}
.school,
.teacher,
.task,
.score,
.class-page,
.teachers {
height: auto !important;
min-height: calc(100vh - 96px);
background: transparent !important;
}
.df,
.online,
.query-bar,
.table-actions,
.demo-form-inline {
color: #cfeaff;
}
.df,
.query-bar {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 12px;
padding: 14px 16px;
border: 1px solid rgba(44, 169, 226, 0.28) !important;
border-radius: 10px;
background: rgba(2, 18, 31, 0.72) !important;
}
.online {
display: inline-flex;
align-items: center;
gap: 8px;
}
.online span,
.el-form-item__label {
color: #cfeaff;
font-weight: 600;
}
.mt10,
.table-actions {
margin-top: 14px;
}
.el-input__wrapper,
.el-select__wrapper,
.el-textarea__inner {
background: rgba(3, 27, 43, 0.88);
border: 1px solid rgba(61, 171, 220, 0.42);
box-shadow: none;
}
.el-input__inner,
.el-select__placeholder,
.el-select__selected-item,
.el-textarea__inner {
color: #eaf7ff;
}
.el-input__inner::placeholder {
color: rgba(189, 221, 244, 0.58);
}
.el-button--primary {
border-color: rgba(48, 185, 255, 0.85);
background: linear-gradient(135deg, #078dce, #1557d6);
box-shadow: 0 8px 18px rgba(0, 110, 220, 0.24);
}
.el-button--warning {
border-color: rgba(245, 166, 35, 0.75);
background: linear-gradient(135deg, #d99620, #b76418);
}
.el-button.is-text {
color: #80d7ff;
}
.el-button--danger.is-text {
color: #ff8d8d;
}
.el-table {
--el-table-border-color: rgba(54, 159, 212, 0.2);
--el-table-header-bg-color: rgba(9, 48, 73, 0.96);
--el-table-tr-bg-color: rgba(2, 16, 27, 0.78);
--el-table-row-hover-bg-color: rgba(0, 111, 177, 0.18);
margin-top: 16px !important;
color: #dff4ff;
border-radius: 10px;
overflow: hidden;
background: transparent;
}
.el-table th.el-table__cell {
color: #dff6ff !important;
font-weight: 700;
background: linear-gradient(180deg, rgba(13, 70, 103, 0.98), rgba(8, 43, 67, 0.98)) !important;
}
.el-table tr,
.el-table td.el-table__cell {
background: rgba(2, 16, 27, 0.72);
}
.el-table__empty-text {
color: #9abed8;
}
.el-card {
color: #e9f7ff;
border: 1px solid rgba(54, 159, 212, 0.28);
background: rgba(4, 20, 33, 0.78);
}
.el-card__header {
border-bottom-color: rgba(54, 159, 212, 0.22);
}
.el-pagination {
margin-top: 16px;
justify-content: flex-end;
color: #cdeaff;
}
.el-tabs__item {
color: #a9cbe1;
}
.el-tabs__item.is-active {
color: #7fe0ff;
}
.el-tabs__active-bar {
background-color: #21c8ff;
}
}
.teacher-dialog {
border: 1px solid rgba(52, 177, 238, 0.42);
border-radius: 12px;
background: linear-gradient(135deg, rgba(6, 24, 38, 0.98), rgba(4, 13, 24, 0.98));
box-shadow: 0 20px 60px rgba(0, 4, 14, 0.55), inset 0 1px 0 rgba(169, 226, 255, 0.08);
.el-dialog__header {
padding: 18px 22px 12px;
border-bottom: 1px solid rgba(52, 177, 238, 0.18);
}
.el-dialog__title {
color: #eef9ff;
font-weight: 700;
}
.el-dialog__body {
color: #d9efff;
}
.el-form-item__label {
color: #cfeaff;
font-weight: 600;
}
.el-input__wrapper,
.el-select__wrapper,
.el-textarea__inner {
background: rgba(3, 27, 43, 0.92);
border: 1px solid rgba(61, 171, 220, 0.42);
box-shadow: none;
}
.el-input__inner,
.el-select__placeholder,
.el-select__selected-item,
.el-textarea__inner {
color: #eaf7ff;
}
}
</style>

@ -1,10 +1,10 @@
<template>
<div class="navbar">
<div :class="['navbar', { 'teacher-navbar': role === 3 }]">
<div :class="[role !== 3 ? 'navTitle' : 'TnavTitle']">
<span class="nacber-name" v-if="role !== 3">电商互联网产品开发实训系统</span>
<span class="nacber-name" v-else>数 字 营 销 实 训 系 统 - 教 师 端</span>
</div>
<div :class="['el-ment', { 'platform-nav': role === 1 || role === 2, 'school-admin-nav': role === 2 }]">
<div :class="['el-ment', { 'platform-nav': role === 1 || role === 2, 'school-admin-nav': role === 2, 'teacher-nav': role === 3 }]">
<template v-for="item in roleList" :key="item.name">
<div :class="['el-ment-item', { 'el-ment-item-active': isActive(item) }]" @click="go(item)">{{ item.name }}</div>
</template>
@ -160,6 +160,55 @@ const mentList = ref([
path: "/ai/teaching-plan",
role: 3,
},
{
name: "院系管理",
path: "/school/index",
role: 3,
teacherMenu: true,
activePrefix: "/school",
},
{
name: "专业管理",
path: "/major/index",
role: 3,
teacherMenu: true,
activePrefix: "/major",
},
{
name: "班级管理",
path: "/class/index",
role: 3,
teacherMenu: true,
activePrefix: "/class",
},
{
name: "教师管理",
path: "/teacher/index",
role: 3,
teacherMenu: true,
activePrefix: "/teacher",
},
{
name: "学生管理",
path: "/student/index",
role: 3,
teacherMenu: true,
activePrefix: "/student",
},
{
name: "任务分配",
path: "/task/index",
role: 3,
teacherMenu: true,
activePrefix: "/task",
},
{
name: "成绩中心",
path: "/score/index",
role: 3,
teacherMenu: true,
activePrefix: "/score",
},
]);
const activement = ref(mentList.value[0]);
function toggleSideBar() {
@ -204,6 +253,10 @@ const isActive = (item) => {
// 根据角色显示菜单
const roleList = computed(() => {
const currentRole = role.value;
if (currentRole === 3) {
const teacherOrder = ["/index", "/school/index", "/major/index", "/class/index", "/teacher/index", "/student/index", "/task/index", "/score/index", "/analysis/index", "/ai/teaching-plan"];
return teacherOrder.map((path) => mentList.value.find((item) => item.path === path)).filter(Boolean);
}
return mentList.value.filter((item) => {
if (currentRole === 1) {
return item.path === "/index" || item.role === 1;
@ -361,6 +414,35 @@ onMounted(() => {
padding: 6px 10px;
}
}
&.teacher-nav {
left: 53%;
z-index: 1002;
max-width: calc(100vw - 560px);
gap: 8px;
font-size: 15px;
overflow-x: auto;
overflow-y: hidden;
padding: 4px 2px;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
.el-ment-item {
padding: 7px 10px;
color: #cde9ff;
border-color: rgba(94, 207, 255, 0.12);
background: rgba(0, 98, 154, 0.08);
}
.el-ment-item-active {
color: #ffffff;
border-color: rgba(70, 202, 255, 0.8);
background: linear-gradient(95deg, rgba(0, 174, 255, 0.34), rgba(36, 96, 255, 0.18));
box-shadow: 0 0 16px rgba(0, 174, 255, 0.24), inset 0 0 14px rgba(133, 217, 255, 0.12);
}
}
}
.right-menu {
float: right;
@ -414,4 +496,33 @@ onMounted(() => {
}
}
}
.teacher-navbar {
background: linear-gradient(180deg, rgba(5, 17, 31, 0.96), rgba(5, 20, 35, 0.9)) !important;
border-bottom: 1px solid rgba(60, 192, 255, 0.34);
box-shadow: 0 8px 24px rgba(0, 8, 20, 0.35);
backdrop-filter: blur(14px);
.TnavTitle {
background: linear-gradient(90deg, rgba(0, 102, 180, 0.38), rgba(4, 18, 35, 0.2) 58%, transparent) !important;
box-shadow: none;
width: 470px;
z-index: 1001;
span {
font-size: 22px;
letter-spacing: 2px;
text-shadow: 0 0 14px rgba(80, 200, 255, 0.28);
}
}
.right-menu {
position: relative;
z-index: 1003;
}
.avatar-container {
margin-right: 28px !important;
}
}
</style>

@ -30,13 +30,14 @@ const sidebar = computed(() => useAppStore().sidebar);
const device = computed(() => useAppStore().device);
const needTagsView = computed(() => settingsStore.tagsView);
const fixedHeader = computed(() => settingsStore.fixedHeader);
const useTopNavbarOnly = computed(() => role.value === 1 || role.value === 2);
const useTopNavbarOnly = computed(() => role.value === 1 || role.value === 2 || role.value === 3);
const classObj = computed(() => ({
hideSidebar: !sidebar.value.opened,
openSidebar: sidebar.value.opened,
withoutAnimation: sidebar.value.withoutAnimation,
mobile: device.value === "mobile",
teacherLayout: role.value === 3,
}));
const { width, height } = useWindowSize();

@ -1,99 +1,89 @@
<!--
* @Author: qinzhenpen qzp1807@126.com
* @Date: 2025-05-13 16:22:46
* @LastEditors: qinzhenpen qzp1807@126.com
* @LastEditTime: 2025-05-22 09:43:12
* @FilePath: \e-commerce-internet\src\views\teacherEnd\school\index.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="class app-container">
<div class="df">
<div class="online">
<span>所属院系:</span>
<!-- <el-input v-model="paramsquery.schoolName" style="width: 150px" type="text" class="ml10" /> -->
<el-select v-model="paramsquery.schoolFacultyId" placeholder="" clearable class="ml10" @change="getMajorList" style="width: 14rem">
<el-option v-for="school in facultyList" :key="school.schoolId" :label="school.schoolFacultyName" :value="school.schoolFacultyId" />
<div class="class-page app-container">
<el-tabs v-model="activeClassType" class="class-tabs" @tab-change="handleTabChange">
<el-tab-pane label="行政班" name="ADMIN" />
<el-tab-pane label="教学班" name="TEACHING" />
</el-tabs>
<div class="query-bar">
<el-select v-model="paramsquery.schoolFacultyId" placeholder="所属院系" clearable class="query-control" @change="getMajorList">
<el-option v-for="faculty in facultyList" :key="faculty.schoolFacultyId" :label="faculty.schoolFacultyName" :value="faculty.schoolFacultyId" />
</el-select>
</div>
<div class="online">
<span>所属专业:</span>
<!-- <el-input v-model="paramsquery.schoolName" style="width: 150px" type="text" class="ml10" /> -->
<el-select v-model="paramsquery.schoolMajorId" placeholder="" clearable class="ml10">
<el-select v-model="paramsquery.schoolMajorId" placeholder="所属专业" clearable class="query-control">
<el-option v-for="major in majorList" :key="major.schoolMajorId" :label="major.schoolMajorName" :value="major.schoolMajorId" />
</el-select>
<el-input v-model="paramsquery.className" placeholder="班级名称" clearable class="query-control" />
<el-button type="primary" :icon="Search" @click="getList">查询</el-button>
<el-button :icon="Refresh" @click="refresh">刷新</el-button>
</div>
<div class="online">
<span>班级名称:</span>
<el-input v-model="paramsquery.className" style="width: 14rem" type="text" class="ml10" />
</div>
<div class="online">
<span>班级编号:</span>
<el-input v-model="paramsquery.classSn" style="width: 14rem" type="text" class="ml10" />
<el-button @click="getList" type="primary" class="ml10" :icon="Search">搜索</el-button>
</div>
<div class="table-actions">
<el-button type="primary" :icon="Plus" @click="openCreateDialog">新增{{ activeClassType === 'ADMIN' ? '行政班' : '教学班' }}</el-button>
</div>
<el-row class="mt10">
<el-col>
<el-button type="primary" :icon="Plus" @click="addschool">新增</el-button>
<el-button type="primary" :icon="Refresh" @click="refresh">刷新</el-button>
</el-col>
</el-row>
<el-table
:data="tableData"
border
v-loading="loading"
style="width: 100%; margin-top: 20px"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="班级名称" prop="schoolClass.className" align="center"></el-table-column>
<el-table-column label="班级编号" prop="schoolClass.classSn" align="center"></el-table-column>
<el-table-column label="创建人" align="center">
<el-table :data="filteredTableData" border v-loading="loading" class="class-table" :header-cell-style="tableHeaderStyle">
<el-table-column label="班级名称" prop="schoolClass.className" align="center" />
<el-table-column label="所属院系" align="center">
<template #default="{ row }">
<span>{{ row.schoolFacultyName || "-" }}</span>
</template>
</el-table-column>
<el-table-column label="所属专业" align="center">
<template #default="{ row }">
<span>{{ row.schoolMajorName || "-" }}</span>
</template>
</el-table-column>
<el-table-column v-if="activeClassType === 'TEACHING'" label="创建人" align="center">
<template #default="{ row }">
<span>{{ row.schoolClass.createdByName || row.schoolClass.createdBy || "-" }}</span>
</template>
</el-table-column>
<el-table-column label="创建日期" prop="schoolClass.createTime" align="center">
<el-table-column label="数据来源" align="center" width="120">
<template #default="{ row }">
<el-tag :type="row.schoolClass.dataSource === 'ZHIYUN' ? 'warning' : 'success'">
{{ row.schoolClass.dataSource === "ZHIYUN" ? "智云" : "本系统" }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="创建时间" prop="schoolClass.createTime" align="center" width="180">
<template #default="{ row }">
<span>{{ formatDate(row.schoolClass.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<el-table-column label="操作" align="center" width="260">
<template #default="{ row }">
<template v-if="canOperateClass(row.schoolClass)">
<el-button type="primary" text @click="editSchool(row.schoolClass)">编辑</el-button>
<el-button type="danger" text @click="delSchool(row.schoolClass.schoolClassId)">删除</el-button>
<el-button type="primary" text @click="handleSuccess(row)">数据初始化</el-button>
<el-button type="primary" text @click="editClass(row.schoolClass)">编辑</el-button>
<el-button type="danger" text @click="deleteClass(row.schoolClass.schoolClassId)">删除</el-button>
<el-button v-if="activeClassType === 'TEACHING'" type="warning" text @click="initializeClass(row.schoolClass)">
数据初始化
</el-button>
</template>
<el-tag v-else type="info">仅查看</el-tag>
</template>
</el-table-column>
</el-table>
<pagination v-show="schoolTotal > 0" :total="schoolTotal" v-model:page="paramsquery.index" v-model:limit="paramsquery.size" @pagination="getList" />
<el-dialog v-model="dialogVisible" top="110vh" width="50%" :title="`新增院系`" :modal="false" @close="onClose">
<el-form :model="formInline" class="demo-form-inline" ref="formInlineref" label-width="100px" style="width: 80%" :rules="rules">
<el-form-item label="所属院系:" prop="schoolFacultyId">
<el-select v-model="formInline.schoolFacultyId" placeholder="" clearable @change="getMajorList1" style="width: 20rem" v-if="status">
<el-option v-for="school in facultyList" :key="school.schoolId" :label="school.schoolFacultyName" :value="school.schoolFacultyId" />
<el-dialog v-model="dialogVisible" width="520px" :title="dialogTitle" class="teacher-dialog" @close="onClose">
<el-form ref="formInlineref" :model="formInline" label-width="96px" :rules="rules">
<el-form-item label="所属院系" prop="schoolFacultyId">
<el-select v-model="formInline.schoolFacultyId" placeholder="请选择院系" clearable class="form-control" @change="getMajorListForForm" :disabled="!isCreate">
<el-option v-for="faculty in facultyList" :key="faculty.schoolFacultyId" :label="faculty.schoolFacultyName" :value="faculty.schoolFacultyId" />
</el-select>
<el-input v-else v-model="classInfo.name" style="width: 20rem" disabled></el-input>
</el-form-item>
<el-form-item label="所属专业:" prop="schoolMajorId">
<el-select v-model="formInline.schoolMajorId" placeholder="" clearable style="width: 20rem" v-if="status">
<el-option v-for="major in majorList1" :key="major.schoolMajorId" :label="major.schoolMajorName" :value="major.schoolMajorId" />
<el-form-item label="所属专业" prop="schoolMajorId">
<el-select v-model="formInline.schoolMajorId" placeholder="请选择专业" clearable class="form-control" :disabled="!isCreate">
<el-option v-for="major in majorListForForm" :key="major.schoolMajorId" :label="major.schoolMajorName" :value="major.schoolMajorId" />
</el-select>
<el-input v-else v-model="classInfo.value" placeholder="请输入所属专业:" style="width: 20rem" disabled></el-input>
</el-form-item>
<el-form-item label="班级名称:" prop="className">
<el-input v-model="formInline.className" style="width: 20rem" placeholder=""></el-input>
<el-form-item label="班级名称" prop="className">
<el-input v-model="formInline.className" placeholder="请输入班级名称" class="form-control" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footers">
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</span>
@ -101,163 +91,266 @@
</el-dialog>
</div>
</template>
<script setup>
import { Search, Plus, Refresh } from "@element-plus/icons-vue";
import { Plus, Refresh, Search } from "@element-plus/icons-vue";
import { ElMessageBox } from "element-plus";
import { formatDate } from "@/utils/index";
const { proxy } = getCurrentInstance();
import useUserStore from "@/store/modules/user";
import { ElMessageBox } from "element-plus";
import * as indexApi from "@/api/teacher";
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
const currentUserId = computed(() => userStore.userInfo.userId);
import * as indexApi from "@/api/teacher";
const activeClassType = ref("ADMIN");
const dialogVisible = ref(false);
const loading = ref(false);
const formInline = ref({
const isCreate = ref(true);
const tableData = ref([]);
const schoolTotal = ref(0);
const facultyList = ref([]);
const majorList = ref([]);
const majorListForForm = ref([]);
const currentUserId = computed(() => userStore.userInfo.userId);
const currentSchoolId = computed(() => userStore.userInfo.schoolId);
const isManagerTeacher = computed(() => userStore.userInfo.teacherAdmin === true || String(userStore.userInfo.roleId) === "1");
const paramsquery = ref({
index: 1,
size: 10,
schoolId: currentSchoolId.value,
schoolFacultyId: "",
schoolId: userStore.userInfo.schoolId,
schoolMajorId: "",
className: "",
});
const rules = ref({
const formInline = ref(defaultForm());
const rules = {
schoolFacultyId: [{ required: true, message: "请选择所属院系", trigger: "change" }],
schoolMajorId: [{ required: true, message: "请输入所属专业", trigger: "blur" }],
schoolMajorId: [{ required: true, message: "请选择所属专业", trigger: "change" }],
className: [{ required: true, message: "请输入班级名称", trigger: "blur" }],
};
const tableHeaderStyle = {
color: "#0f3052",
fontSize: "14px",
backgroundColor: "#eaf4ff",
};
const dialogTitle = computed(() => `${isCreate.value ? "新增" : "编辑"}${activeClassType.value === "ADMIN" ? "行政班" : "教学班"}`);
const filteredTableData = computed(() => {
return tableData.value.filter((row) => normalizeClassType(row.schoolClass) === activeClassType.value);
});
const paramsquery = ref({
index: 1,
size: 10,
classSn: "",
schoolId: userStore.userInfo.schoolId,
function defaultForm() {
return {
schoolFacultyId: "",
schoolId: currentSchoolId.value,
schoolMajorId: "",
className: "",
});
const classInfo = ref({});
const schoolTotal = ref(0);
// 新增编辑状态
const status = ref(false);
// 院校list
const tableData = ref([]);
// 获取院校列表
const getList = () => {
indexApi.getClassesList(paramsquery.value).then((res) => {
tableData.value = res.data.list;
schoolTotal.value = res.data.total;
});
classType: activeClassType.value,
sourceClassIds: "",
};
// 删除院校
const delSchool = (id) => {
indexApi.deleteClass({ schoolClassId: id, userId: userStore.userInfo.userId }).then((res) => {
proxy.$message.success("删除成功");
getList();
}
function normalizeClassType(schoolClass) {
if (schoolClass?.classType) {
return schoolClass.classType;
}
return schoolClass?.createdBy ? "TEACHING" : "ADMIN";
}
function canOperateClass(schoolClass) {
if (schoolClass?.dataSource === "ZHIYUN") {
return false;
}
if (normalizeClassType(schoolClass) === "TEACHING") {
return schoolClass?.createdBy === currentUserId.value;
}
return isManagerTeacher.value || schoolClass?.createdBy === currentUserId.value;
}
function getList() {
loading.value = true;
indexApi
.getClassesList(paramsquery.value)
.then((res) => {
tableData.value = res.data?.list || [];
schoolTotal.value = res.data?.total || 0;
})
.finally(() => {
loading.value = false;
});
};
// 新增院校
const addschool = () => {
}
function handleTabChange() {
paramsquery.value.index = 1;
getList();
}
function openCreateDialog() {
isCreate.value = true;
formInline.value = defaultForm();
dialogVisible.value = true;
status.value = true;
}
function editClass(row) {
isCreate.value = false;
formInline.value = {
...row,
classType: normalizeClassType(row),
userId: currentUserId.value,
};
const editSchool = (row) => {
let data = { ...row };
formInline.value = data;
dialogVisible.value = true;
status.value = false;
indexApi.getFacultyAndMajorName({ schoolMajorId: row.schoolMajorId }).then((res) => {
classInfo.value.name = Object.keys(res.data)[0];
classInfo.value.value = Object.values(res.data)[0];
});
}
function addClass() {
const payload = {
...formInline.value,
schoolId: currentSchoolId.value,
classType: activeClassType.value,
userId: currentUserId.value,
};
const add = () => {
formInline.value.userId = currentUserId.value;
indexApi.addClass(formInline.value).then((res) => {
indexApi.addClass(payload).then(() => {
proxy.$message.success("添加成功");
dialogVisible.value = false;
getList();
});
}
function updateClass() {
const payload = {
...formInline.value,
schoolId: currentSchoolId.value,
classType: activeClassType.value,
userId: currentUserId.value,
status: true,
};
const edit = () => {
formInline.value.schoolId = userStore.userInfo.schoolId;
formInline.value.userId = currentUserId.value;
formInline.value.status = true;
indexApi.updateClass(formInline.value).then((res) => {
indexApi.updateClass(payload).then(() => {
proxy.$message.success("编辑成功");
dialogVisible.value = false;
getList();
});
};
const canOperateClass = (schoolClass) => {
return schoolClass?.createdBy === currentUserId.value;
};
// 提交
const submitForm = () => {
status.value ? add() : edit();
};
const onClose = () => {
for (const key in formInline.value) {
formInline.value[key] = "";
}
dialogVisible.value = false;
};
// 刷新
const refresh = () => {
loading.value = true;
setTimeout(() => {
loading.value = false;
getList();
}, 2000);
};
// 查询院系下拉列表
const facultyList = ref([]);
const getFacultyList = () => {
indexApi.seleteSchoolFacultyList({ schoolId: userStore.userInfo.schoolId }).then((res) => {
facultyList.value = res.data;
function submitForm() {
proxy.$refs.formInlineref.validate((valid) => {
if (!valid) return;
isCreate.value ? addClass() : updateClass();
});
};
// 专业下拉框
const majorList = ref([]);
const getMajorList = () => {
if (!paramsquery.value.schoolFacultyId) return;
paramsquery.value.schoolMajorId = "";
indexApi.getMajorListBySchoolId({ schoolFacultyId: paramsquery.value.schoolFacultyId }).then((res) => {
majorList.value = res.data;
}
function deleteClass(id) {
ElMessageBox.confirm("确定删除该班级吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
indexApi.deleteClass({ schoolClassId: id, userId: currentUserId.value }).then(() => {
proxy.$message.success("删除成功");
getList();
});
};
// 专业下拉框
const majorList1 = ref([]);
const getMajorList1 = () => {
indexApi.getMajorListBySchoolId({ schoolFacultyId: formInline.value.schoolFacultyId }).then((res) => {
majorList1.value = res.data;
});
};
//案例初始话方法
const handleSuccess = (res) => {
ElMessageBox.confirm("确定初始化班级数据吗?", "提示", {
}
function initializeClass(schoolClass) {
ElMessageBox.confirm("确定初始化该教学班全班实训数据吗?该操作不可恢复。", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
indexApi
.initializeTeachingClassTrainingData({
teachingClassId: schoolClass.schoolClassId,
operatorId: currentUserId.value,
})
.then(() => {
indexApi.initClass({ classId: res.schoolClass.schoolClassId}).then((res) => {
proxy.$message.success("初始化成功");
});
});
}
function refresh() {
getList();
}
function onClose() {
formInline.value = defaultForm();
}
function getFacultyList() {
indexApi.seleteSchoolFacultyList({ schoolId: currentSchoolId.value }).then((res) => {
facultyList.value = res.data || [];
});
})
.catch(() => {});
};
}
function getMajorList() {
paramsquery.value.schoolMajorId = "";
if (!paramsquery.value.schoolFacultyId) {
majorList.value = [];
return;
}
indexApi.getMajorListBySchoolId({ schoolFacultyId: paramsquery.value.schoolFacultyId }).then((res) => {
majorList.value = res.data || [];
});
}
function getMajorListForForm() {
formInline.value.schoolMajorId = "";
if (!formInline.value.schoolFacultyId) {
majorListForForm.value = [];
return;
}
indexApi.getMajorListBySchoolId({ schoolFacultyId: formInline.value.schoolFacultyId }).then((res) => {
majorListForForm.value = res.data || [];
});
}
onMounted(() => {
getList();
getFacultyList();
});
</script>
<style lang='scss' scoped>
.class {
background: #ffffff;
height: calc(100vh - 70px);
.df {
<style lang="scss" scoped>
.class-page {
min-height: calc(100vh - 70px);
background: #f7fbff;
.class-tabs {
margin-bottom: 12px;
}
.query-bar {
display: flex;
align-items: center;
// 换行
flex-wrap: wrap;
gap: 20px;
align-items: center;
gap: 12px;
padding: 14px;
border: 1px solid #d8e8f7;
border-radius: 6px;
background: #ffffff;
}
.query-control {
width: 220px;
}
.table-actions {
display: flex;
justify-content: flex-start;
margin: 14px 0;
}
.class-table {
width: 100%;
}
.form-control {
width: 100%;
}
}
</style>

@ -24,7 +24,7 @@
</div>
<el-row class="mt10">
<el-col>
<el-button type="primary" :icon="Plus" @click="addschool">新增</el-button>
<el-button v-if="isManagerTeacher" type="primary" :icon="Plus" @click="addschool">新增</el-button>
<el-button type="primary" :icon="Refresh" @click="refresh">刷新</el-button>
</el-col>
</el-row>
@ -50,13 +50,16 @@
</el-table-column>
<el-table-column label="操作" align="center">
<template #default="{ row }">
<template v-if="isManagerTeacher">
<el-button type="primary" text @click="editSchool(row.schoolMajor, row.schoolMajorId)">编辑</el-button>
<el-button type="danger" text @click="delSchool(row.schoolMajorId)">删除</el-button>
</template>
<el-tag v-else type="info">仅查看</el-tag>
</template>
</el-table-column>
</el-table>
<pagination v-show="schoolTotal > 0" :total="schoolTotal" v-model:page="paramsquery.index" v-model:limit="paramsquery.size" @pagination="getList" />
<el-dialog v-model="dialogVisible" top="110vh" width="50%" :title="`新增院系`" :modal="false" @close="onClose">
<el-dialog v-model="dialogVisible" width="560px" :title="`新增专业`" class="teacher-dialog" @close="onClose">
<el-form :model="formInline" class="demo-form-inline" ref="formInlineref" label-width="100px" style="width: 80%">
<el-form-item label="所属院系:" prop="schoolFacultyId">
<el-select v-model="formInline.schoolFacultyId" placeholder="" clearable style="width: 20rem">
@ -91,6 +94,8 @@ const userStore = useUserStore();
import * as indexApi from "@/api/teacher";
const dialogVisible = ref(false);
const loading = ref(false);
const currentUserId = computed(() => userStore.userInfo.userId);
const isManagerTeacher = computed(() => userStore.userInfo.teacherAdmin === true || String(userStore.userInfo.roleId || userStore.userInfo.role) === "1");
const formInline = ref({
schoolFacultyId: "",
schoolId: userStore.userInfo.schoolId,
@ -139,6 +144,8 @@ const editSchool = (row, id) => {
status.value = false;
};
const add = () => {
formInline.value.userId = currentUserId.value;
formInline.value.schoolId = userStore.userInfo.schoolId;
indexApi.addMajor(formInline.value).then((res) => {
proxy.$message.success("添加成功");
dialogVisible.value = false;
@ -146,6 +153,7 @@ const add = () => {
};
const edit = () => {
formInline.value.schoolId = userStore.userInfo.schoolId;
formInline.value.userId = currentUserId.value;
formInline.value.status = true;
indexApi.updateMajor(formInline.value).then((res) => {
proxy.$message.success("添加成功");

@ -15,7 +15,7 @@
</div>
<el-row class="mt10">
<el-col>
<el-button type="primary" :icon="Plus" @click="addschool">新增</el-button>
<el-button v-if="isManagerTeacher" type="primary" :icon="Plus" @click="addschool">新增</el-button>
<el-button type="primary" :icon="Refresh" @click="refresh">刷新</el-button>
</el-col>
</el-row>
@ -41,13 +41,16 @@
</el-table-column>
<el-table-column label="操作" align="center">
<template #default="{ row }">
<template v-if="isManagerTeacher">
<el-button type="primary" text @click="editSchool(row)">编辑</el-button>
<el-button type="danger" text @click="delSchool(row.schoolFacultyId)">删除</el-button>
</template>
<el-tag v-else type="info">仅查看</el-tag>
</template>
</el-table-column>
</el-table>
<pagination v-show="schoolTotal > 0" :total="schoolTotal" v-model:page="paramsquery.index" v-model:limit="paramsquery.size" @pagination="getList" />
<el-dialog v-model="dialogVisible" top="110vh" width="50%" :title="`新增院校`" :modal="false" @close="onClose">
<el-dialog v-model="dialogVisible" width="560px" :title="`新增院系`" class="teacher-dialog" @close="onClose">
<el-form :model="formInline" class="demo-form-inline" ref="formInlineref" label-width="100px" :rules="rules">
<el-form-item label="院系名称:" prop="schoolFacultyName">
<el-input v-model="formInline.schoolFacultyName" placeholder="院系名称" clearable />
@ -80,6 +83,8 @@ const userStore = useUserStore();
import * as indexApi from "@/api/teacher";
const dialogVisible = ref(false);
const loading = ref(false);
const currentUserId = computed(() => userStore.userInfo.userId);
const isManagerTeacher = computed(() => userStore.userInfo.teacherAdmin === true || String(userStore.userInfo.roleId || userStore.userInfo.role) === "1");
const formInline = ref({
schoolFacultyName: "",
schoolFacultyContact: "",
@ -128,6 +133,8 @@ const editSchool = (row) => {
status.value = false;
};
const add = () => {
formInline.value.userId = currentUserId.value;
formInline.value.schoolId = userStore.userInfo.schoolId;
indexApi.addSchool(formInline.value).then((res) => {
proxy.$message.success("添加成功");
dialogVisible.value = false;
@ -135,7 +142,7 @@ const add = () => {
});
};
const edit = () => {
formInline.value.userId = userStore.userInfo.userId;
formInline.value.userId = currentUserId.value;
indexApi.updateSchool(formInline.value).then((res) => {
proxy.$message.success("添加成功");
dialogVisible.value = false;

@ -55,7 +55,7 @@
</div>
</div>
<pagination v-show="workingCapitalTotal > 0" :total="workingCapitalTotal" v-model:page="scoreParams.index" v-model:limit="scoreParams.size" @pagination="getList" />
<el-dialog v-model="WeightStart" title="权重设置" width="500" class="F_dialog">
<el-dialog v-model="WeightStart" title="权重设置" width="500" class="F_dialog teacher-dialog">
<el-form ref="ruleFormRef" :model="scoreWeightObj" class="demo-form" :rules="rules">
<el-form-item label="市场需求挖掘:" prop="marketResearchWeight" label-width="150">
<el-input v-model.number="scoreWeightObj.marketResearchWeight" placeholder="" clearable>
@ -90,7 +90,7 @@
</div>
</template>
</el-dialog>
<el-dialog v-model="scoreDetailsStart" title="成绩详情" width="50%" class="F_dialog">
<el-dialog v-model="scoreDetailsStart" title="成绩详情" width="50%" class="F_dialog teacher-dialog">
<el-table
:data="tableData"
border

@ -12,7 +12,7 @@
<div class="online">
<span>班级:</span>
<el-select v-model="paramsquery.schoolClassId" placeholder="" style="width: 14rem" clearable class="ml10" @change="getMajorList">
<el-option v-for="school in classList" :key="school.schoolClassId" :label="school.className" :value="school.schoolClassId" />
<el-option v-for="school in teachingClassList" :key="school.schoolClassId" :label="school.className" :value="school.schoolClassId" />
</el-select>
</div>
<div class="online">
@ -74,7 +74,7 @@
</el-table-column>
</el-table>
<pagination v-show="schoolTotal > 0" :total="schoolTotal" v-model:page="paramsquery.index" v-model:limit="paramsquery.size" @pagination="getList" />
<el-dialog v-model="dialogVisible" top="110vh" width="50%" :title="status ? '新增学生' : '编辑学生'" :modal="false" @close="onClose">
<el-dialog v-model="dialogVisible" width="560px" :title="status ? '新增学生' : '编辑学生'" class="teacher-dialog" @close="onClose">
<el-form :model="formInline" class="demo-form-inline" ref="formInlineref" label-width="100px" style="width: 80%" :rules="rules">
<el-form-item label="所属院系:" prop="schoolFacultyId">
<el-select v-model="formInline.schoolFacultyId" placeholder="" clearable @change="getMajorList" style="width: 20rem" v-if="status">
@ -273,11 +273,17 @@ const downloadTemplate = () => {
};
// 查询班级下拉
const classList = ref([]);
const normalizeClassType = (schoolClass) => {
if (schoolClass?.classType) return schoolClass.classType;
return schoolClass?.createdBy ? "TEACHING" : "ADMIN";
};
const teachingClassList = computed(() => classList.value.filter((item) => normalizeClassType(item) === "TEACHING"));
const classOwnerMap = computed(() => {
return new Map(classList.value.map((item) => [item.schoolClassId, item.createdBy]));
});
const canOperateStudent = (row) => {
return classOwnerMap.value.get(row.schoolClassId) === currentUserId.value;
const teachingClassId = paramsquery.value.schoolClassId || row.schoolClassId;
return classOwnerMap.value.get(teachingClassId) === currentUserId.value;
};
const getClassList = () => {
indexApi.getClassListBySchoolId({ schoolId: userStore.userInfo.schoolId }).then((res) => {
@ -290,7 +296,7 @@ const getClassByMajor = () => {
if (!formInline.value.schoolMajorId) return;
formInline.value.schoolClassId = "";
indexApi.getClassListByMajorId({ schoolMajorId: formInline.value.schoolMajorId }).then((res) => {
classList1.value = (res.data || []).filter((item) => item.createdBy === currentUserId.value);
classList1.value = (res.data || []).filter((item) => normalizeClassType(item) === "TEACHING" && item.createdBy === currentUserId.value);
});
};
//初始化密码
@ -315,7 +321,15 @@ const initPassword = (row, status) => {
type: "warning",
})
.then(() => {
indexApi.initClass({ userId: row.userId }).then((res) => {
if (!paramsquery.value.schoolClassId) {
proxy.$message.warning("请先选择教学班");
return;
}
indexApi.initializeTeachingClassStudentTrainingData({
teachingClassId: paramsquery.value.schoolClassId,
studentUserId: row.userId,
operatorId: currentUserId.value,
}).then((res) => {
proxy.$message.success("初始化成功");
getList();
});

@ -22,12 +22,12 @@
<el-row class="mt10">
<el-col>
<div style="display: flex; gap: 10px">
<el-button type="primary" :icon="Plus" @click="addschool">新增</el-button>
<el-upload action="http://192.168.2.12:7548/api/user/uploadTeacherUserInfo" :show-file-list="false" :on-success="(res, file) => handleSuccess(res, file)">
<el-button type="primary" @click="editSchool(row)">导入</el-button>
<el-button v-if="isManagerTeacher" type="primary" :icon="Plus" @click="addschool">新增</el-button>
<el-upload v-if="isManagerTeacher" action="/api/user/uploadTeacherUserInfo" :data="{ operatorId: currentUserId }" :show-file-list="false" :on-success="(res, file) => handleSuccess(res, file)">
<el-button type="primary">导入</el-button>
</el-upload>
<el-button type="warning" @click="exportTeacher">导出</el-button>
<el-button type="warning" @click="downloadTemplate">导入模版下载</el-button>
<el-button v-if="isManagerTeacher" type="warning" @click="downloadTemplate">导入模版下载</el-button>
<el-button type="primary" :icon="Refresh" @click="refresh">刷新</el-button>
</div>
</el-col>
@ -54,13 +54,16 @@
</el-table-column>
<el-table-column label="操作" align="center">
<template #default="{ row }">
<template v-if="isManagerTeacher">
<el-button type="primary" text @click="editSchool(row)">编辑</el-button>
<el-button type="danger" text @click="delSchool(row)">删除</el-button>
</template>
<el-tag v-else type="info">仅查看</el-tag>
</template>
</el-table-column>
</el-table>
<pagination v-show="schoolTotal > 0" :total="schoolTotal" v-model:page="paramsquery.index" v-model:limit="paramsquery.size" @pagination="getList" />
<el-dialog v-model="dialogVisible" top="110vh" width="50%" :title="status ? '新增教师' : '编辑教师'" :modal="false" @close="onClose">
<el-dialog v-model="dialogVisible" width="560px" :title="status ? '新增教师' : '编辑教师'" class="teacher-dialog" @close="onClose">
<el-form :model="formInline" class="demo-form-inline" ref="formInlineref" label-width="100px" style="width: 80%" :rules="rules">
<el-form-item label="所属院系:" prop="schoolFacultyId">
<el-select v-model="formInline.schoolFacultyId" placeholder="" clearable @change="getMajorList" style="width: 20rem" v-if="status">
@ -106,6 +109,8 @@ const userStore = useUserStore();
import * as indexApi from "@/api/teacher";
const dialogVisible = ref(false);
const loading = ref(false);
const currentUserId = computed(() => userStore.userInfo.userId);
const isManagerTeacher = computed(() => userStore.userInfo.teacherAdmin === true || String(userStore.userInfo.roleId || userStore.userInfo.role) === "1");
const formInline = ref({
schoolFacultyId: "",
schoolId: userStore.userInfo.schoolId,
@ -142,7 +147,7 @@ const getList = () => {
};
// 删除院校
const delSchool = (id) => {
indexApi.deleteTeacher({ userId: id.userId }).then((res) => {
indexApi.deleteTeacher({ userId: id.userId, operatorId: currentUserId.value }).then((res) => {
proxy.$message.success("删除成功");
getList();
});
@ -166,6 +171,7 @@ const editSchool = (row) => {
};
const add = () => {
formInline.value.schoolMajorName = majorList.value?.filter((item) => item.schoolMajorId == formInline.value.schoolMajorId)[0].schoolMajorName;
formInline.value.operatorId = currentUserId.value;
indexApi.addTeacher(formInline.value).then((res) => {
proxy.$message.success("添加成功");
dialogVisible.value = false;
@ -174,6 +180,8 @@ const add = () => {
};
const edit = () => {
formInline.value.status = true;
formInline.value.operatorId = currentUserId.value;
formInline.value.username = formInline.value.userName;
indexApi.updateTeacher(formInline.value).then((res) => {
proxy.$message.success("编辑成功");
dialogVisible.value = false;

Loading…
Cancel
Save