init
This commit is contained in:
+211
@@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<div id="app" v-if="isLogin">
|
||||
<layout :layoutData="layoutData" ref="layout"></layout>
|
||||
<div :class="['base-wrap-main', layoutData.isAlone ? 'alone-page' : '']">
|
||||
<template v-if="!isNoAuthority">
|
||||
<transition name="fade" mode="out-in">
|
||||
<router-view v-if="isRouterAlive"></router-view>
|
||||
</transition>
|
||||
</template>
|
||||
<div v-else class="no-authority-wrap">
|
||||
<h3>暂无权限</h3>
|
||||
<h6>如需查看,请联络管理员为您分配权限</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import layout from "@/frame/layout";
|
||||
const appendLink = (baseHost, name, version) => {
|
||||
var headHTML = `<link type="text/css" rel="stylesheet" href="${baseHost}/BschHome/front/css/${name}.css?v=${version}">`;
|
||||
$("head:eq(0)").append(headHTML);
|
||||
};
|
||||
export default {
|
||||
name: "App",
|
||||
data() {
|
||||
return {
|
||||
isRouterAlive: true,
|
||||
isFull: false,
|
||||
isLogin: false,
|
||||
layoutData: {},
|
||||
isNoAuthority: false,
|
||||
};
|
||||
},
|
||||
components: { layout },
|
||||
provide() {
|
||||
return {
|
||||
reload: this.reload,
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
const _this = this;
|
||||
try {
|
||||
var data = await this.getLayoutData();
|
||||
const baseHost = data.pageUrl.replace("/v/", "");
|
||||
var version = localStorage.getItem("themeVersion");
|
||||
appendLink(baseHost, "base.layout", version ? version : new Date().getTime());
|
||||
var bschResult = await this.getBschHomeJsonp(baseHost, data.id);
|
||||
|
||||
this.setCurrentRole(bschResult, baseHost);
|
||||
data = await this.getLayoutData();
|
||||
this.layoutInit(data, bschResult.appList, baseHost);
|
||||
this.isLogin = true;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.$Message.error("载入用户信息失败!");
|
||||
}
|
||||
//console.log(process.env);
|
||||
},
|
||||
methods: {
|
||||
reload() {
|
||||
this.isRouterAlive = false;
|
||||
this.$nextTick(() => (this.isRouterAlive = true));
|
||||
},
|
||||
getLayoutData() {
|
||||
const _this = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
_this.$api.get(
|
||||
APIConfig.Base.GetLayout,
|
||||
null,
|
||||
resp => {
|
||||
resolve(resp.data);
|
||||
},
|
||||
error => {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
getBschHomeJsonp(baseHost, userId) {
|
||||
var version = localStorage.getItem("themeVersion") || new Date().getTime();
|
||||
return new Promise((resolve, reject) => {
|
||||
var crossStorage,
|
||||
crossUrl = `${baseHost}/BschHome/front/libs/cross`;
|
||||
try {
|
||||
var HEAD = document.getElementsByTagName("head")[0];
|
||||
var node = document.createElement("script");
|
||||
node.src = `${crossUrl}/client.js?v=${version}`;
|
||||
node.onload = function () {
|
||||
crossStorage = new Client(`${crossUrl}/middle.html?v=${version}`, () => {
|
||||
crossStorage.getRoteData({ userId }, resp => {
|
||||
resolve(resp);
|
||||
});
|
||||
});
|
||||
|
||||
//分页数据默认条数
|
||||
const customPageCount = localStorage.getItem("customPageCount");
|
||||
crossStorage.getItem("customPageCount", resp => {
|
||||
if (resp == null) return false;
|
||||
if (customPageCount == null) localStorage.setItem("customPageCount", resp);
|
||||
else if (resp != customPageCount) {
|
||||
crossStorage.setItem({
|
||||
key: "customPageCount",
|
||||
value: customPageCount,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
HEAD.appendChild(node);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
},
|
||||
layoutInit(data, appList, baseHost) {
|
||||
this.layoutData.appName = data.topName;
|
||||
this.layoutData.baseHost = baseHost;
|
||||
this.layoutData.ssoHost = data.ssoUrl;
|
||||
let arr = [];
|
||||
const routes = this.$router.options.routes;
|
||||
data.pathList.forEach(element => {
|
||||
let iconIndex = routes.findIndex(x => typeof x.meta !== "undefined" && typeof x.meta.modId !== "undefined" && typeof x.meta.icon !== "undefined" && x.meta.modId == element.modId);
|
||||
let icon = iconIndex > -1 ? "iconfont " + routes[iconIndex].meta.icon : ""; //icon不传则为默认
|
||||
arr.push({
|
||||
id: element.id,
|
||||
name: element.name,
|
||||
modId: element.modId,
|
||||
page: element.page,
|
||||
children: element.children || [],
|
||||
icon, //icon不传则为默认
|
||||
});
|
||||
});
|
||||
// arr[0].icon = "iconfont icon-qunzu"; //icon样式示例,参见static/style/font 目录
|
||||
//console.log(arr);
|
||||
this.layoutData.modList = arr.sort((a, b) => a.modId - b.modId);
|
||||
this.layoutData.isAlone = arr.length == 1; //当只有一个选项卡时,隐藏menu和nav
|
||||
// let { id, name, profilePicture } = data;
|
||||
let { id, username, avatar } = data;
|
||||
this.layoutData.userInfo = { id, name: username, avatar };
|
||||
this.layoutData.appList = appList || [];
|
||||
//无权限
|
||||
if (arr.length == 0) {
|
||||
this.layoutData.isAlone = true;
|
||||
this.isNoAuthority = true;
|
||||
}
|
||||
},
|
||||
setCurrentRole(result, baseHost) {
|
||||
if (result) {
|
||||
let { childId, roleId, schId } = result.checkRole;
|
||||
localStorage.setItem("currentRole", encodeURI(JSON.stringify({ childId, roleId, schId })));
|
||||
localStorage.setItem("themeVersion", result.themeVersion);
|
||||
appendLink(baseHost, result.themeName, result.themeVersion);
|
||||
} else {
|
||||
appendLink(baseHost, "default-theme", new Date().getTime());
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
#loging-box {
|
||||
display: none;
|
||||
}
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: all 1ms cubic-bezier(0, 0.99, 1, 0.03);
|
||||
}
|
||||
/* 进入开始 */
|
||||
.fade-enter {
|
||||
// transform: translateY(10px);
|
||||
opacity: 0;
|
||||
}
|
||||
/* 出去终点 */
|
||||
.fade-leave-active {
|
||||
// transform: translateY(-10px);
|
||||
// opacity: 0;
|
||||
}
|
||||
|
||||
.back-enter-active,
|
||||
.back-leave-active {
|
||||
transition: all 1ms cubic-bezier(0, 0.99, 1, 0.03);
|
||||
}
|
||||
/* 进入开始 */
|
||||
.back-enter {
|
||||
display: none;
|
||||
}
|
||||
/* 出去终点 */
|
||||
.back-leave-active {
|
||||
display: none;
|
||||
}
|
||||
.main-wrap {
|
||||
padding: 120px 0 0 200px;
|
||||
height: 100%;
|
||||
}
|
||||
.main-panel {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
padding: 15px;
|
||||
}
|
||||
.main-panel.is-page {
|
||||
height: calc(100% - 60px);
|
||||
}
|
||||
|
||||
.full {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
<template>
|
||||
<div id="app" v-if="isLogin">
|
||||
<layout-old v-if="isLayoutOld" :layoutData="layoutData"></layout-old>
|
||||
<layout v-else :layoutData="layoutData"></layout>
|
||||
<div :class="['base-wrap-main', layoutData.isAlone ? 'alone-page' : '']">
|
||||
<transition v-if="!isNoAuthority" :name="!isBack ? 'fade' : 'back'" :mode="!isBack ? 'out-in' : 'in-out'">
|
||||
<router-view v-if="isRouterAlive"></router-view>
|
||||
</transition>
|
||||
<div v-else class="no-authority-wrap">
|
||||
<h3>暂无权限</h3>
|
||||
<h6>如需查看,请联络管理员为您分配权限</h6>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <Modal v-model="isAlertModal" :closable="false" :mask-closable="false" title="更新提示" width="830">
|
||||
<Alert show-icon>
|
||||
因为铃铛等环境无法同一时间更新,为不影响正在运行的项目,所以新的标准样式名称改为base.layout.beta.css
|
||||
</Alert>
|
||||
<p>
|
||||
<img width="100%" src="./assets/image/1636426109.jpg" alt="" />
|
||||
</p>
|
||||
</Modal> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import layout from "./frame/layout.vue";
|
||||
import layoutOld from "./frame/layout_old.vue";
|
||||
|
||||
const appendLink = (baseHost, name, version) => {
|
||||
var headHTML = `<link type="text/css" rel="stylesheet" href="${baseHost}/BschHome/front/css/${name}.css?v=${version}">`;
|
||||
$("head:eq(0)").append(headHTML);
|
||||
};
|
||||
|
||||
export default {
|
||||
components: { layout, layoutOld },
|
||||
name: "app",
|
||||
data() {
|
||||
return {
|
||||
isRouterAlive: true,
|
||||
isBack: false,
|
||||
isLogin: false,
|
||||
isNoAuthority: false,
|
||||
layoutData: {},
|
||||
isLayoutOld: conf.isLayoutOld,
|
||||
isAlertModal: false,
|
||||
};
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
reload: this.reload,
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
try {
|
||||
const baseHost = window.conf.baseHost,
|
||||
ssoHost = window.conf.ssoHost;
|
||||
var version = localStorage.getItem("themeVersion") || new Date().getTime();
|
||||
appendLink(baseHost, "base.layout.beta", version);
|
||||
var info = await this.getUserInfo();
|
||||
var bschResult = await this.getBschHomeJsonp(baseHost, info.id);
|
||||
this.setCurrentRole(bschResult, baseHost, info.id);
|
||||
var mod = await this.getUserMod();
|
||||
this.layoutInit(info, mod, bschResult.appList, baseHost, ssoHost);
|
||||
|
||||
this.isLogin = true;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.$Message.error("载入用户信息失败!");
|
||||
}
|
||||
|
||||
// this.isAlertModal = true;
|
||||
// if (localStorage.getItem("cook_is_alert") == null) {
|
||||
// localStorage.setItem("cook_is_alert", true);
|
||||
// this.isAlertModal = true;
|
||||
// }
|
||||
},
|
||||
mounted() {
|
||||
var isTrident = navigator.userAgent.indexOf("Trident") > -1; // 是否是IE内核
|
||||
if (isTrident) {
|
||||
$("html").css("overflow", "hidden");
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
reload() {
|
||||
this.isRouterAlive = false;
|
||||
this.$nextTick(() => (this.isRouterAlive = true));
|
||||
},
|
||||
getUserInfo() {
|
||||
const _this = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
_this.$api.get(
|
||||
APIConfig.Base.GetUserInfo,
|
||||
null,
|
||||
resp => {
|
||||
resolve(resp.data);
|
||||
},
|
||||
error => reject(error)
|
||||
);
|
||||
});
|
||||
},
|
||||
getUserMod() {
|
||||
const _this = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
_this.$api.get(
|
||||
APIConfig.Base.GetUserMod,
|
||||
null,
|
||||
resp => {
|
||||
let resps={"code":0,"msg":"","data":
|
||||
[
|
||||
{"id":1493,"appId":551,"modId":1,"name":"学制选择","parentId":0,"path":null,"level":0,"page":"/","icon":null,"orderNumber":1493,"usable":true,"children":[],"modules":[]},
|
||||
{"id":1494,"appId":551,"modId":2,"name":"时段设置","parentId":0,"path":null,"level":0,"page":"/itemSet","icon":null,"orderNumber":1494,"usable":true,"children":[],"modules":[]},
|
||||
{"id":1494,"appId":551,"modId":3,"name":"区域操作日志","parentId":0,"path":null,"level":0,"page":"/areaOperateDaily","icon":null,"orderNumber":1494,"usable":true,"children":[],"modules":[]},
|
||||
{"id":1494,"appId":551,"modId":4,"name":"学校设置","parentId":0,"path":null,"level":0,"page":"/schoolSetting","icon":null,"orderNumber":1494,"usable":true,"children":[],"modules":[]},
|
||||
{"id":1494,"appId":551,"modId":5,"name":"课程设置","parentId":0,"path":null,"level":0,"page":"/subjectManForZy","icon":null,"orderNumber":1494,"usable":true,"children":[],"modules":[]},
|
||||
{"id":1494,"appId":551,"modId":6,"name":"学科管理","parentId":0,"path":null,"level":0,"page":"/subjectSetzhi","icon":null,"orderNumber":1494,"usable":true,"children":[],"modules":[]},
|
||||
{"id":1494,"appId":551,"modId":7,"name":"班级管理","parentId":0,"path":null,"level":0,"page":"/classManage","icon":null,"orderNumber":1494,"usable":true,"children":[],"modules":[]},
|
||||
{"id":1494,"appId":551,"modId":8,"name":"选修班管理","parentId":0,"path":null,"level":0,"page":"/electiveClassManage","icon":null,"orderNumber":1494,"usable":true,"children":[],"modules":[]},
|
||||
{"id":1494,"appId":551,"modId":9,"name":"教师管理","parentId":0,"path":null,"level":0,"page":"/teacherManage","icon":null,"orderNumber":1494,"usable":true,"children":[],"modules":[]},
|
||||
{"id":1494,"appId":551,"modId":10,"name":"学生管理","parentId":0,"path":null,"level":0,"page":"/studentManage","icon":null,"orderNumber":1494,"usable":true,"children":[],"modules":[]},
|
||||
{"id":1494,"appId":551,"modId":11,"name":"历史查询","parentId":0,"path":null,"level":0,"page":"/historySearch","icon":null,"orderNumber":1494,"usable":true,"children":[],"modules":[]},
|
||||
{"id":1494,"appId":551,"modId":12,"name":"学生异动管理","parentId":0,"path":null,"level":0,"page":"/studentYDManage","icon":null,"orderNumber":1494,"usable":true,"children":[],"modules":[]},
|
||||
{"id":1494,"appId":551,"modId":13,"name":"教师转入管理","parentId":0,"path":null,"level":0,"page":"/zhuanruinfo","icon":null,"orderNumber":1494,"usable":true,"children":[],"modules":[]},
|
||||
{"id":1494,"appId":551,"modId":14,"name":"学生转入管理","parentId":0,"path":null,"level":0,"page":"/zhuanruinfostu","icon":null,"orderNumber":1494,"usable":true,"children":[],"modules":[]},
|
||||
{"id":1494,"appId":551,"modId":15,"name":"日志管理","parentId":0,"path":null,"level":0,"page":"/dailySearch","icon":null,"orderNumber":1494,"usable":true,"children":[],"modules":[]},
|
||||
],"timeNow":"2026-06-17 14:44:05"}
|
||||
resolve(resps.data);
|
||||
},
|
||||
error => reject(error)
|
||||
);
|
||||
});
|
||||
},
|
||||
getBschHomeJsonp(baseHost, userId) {
|
||||
var version = localStorage.getItem("themeVersion") || new Date().getTime();
|
||||
return new Promise((resolve, reject) => {
|
||||
var crossStorage,
|
||||
crossUrl = `${baseHost}/BschHome/front/libs/cross`;
|
||||
try {
|
||||
var HEAD = document.getElementsByTagName("head")[0];
|
||||
var node = document.createElement("script");
|
||||
node.src = `${crossUrl}/client.js?v=${version}`;
|
||||
node.onload = function () {
|
||||
crossStorage = new Client(`${crossUrl}/middle.html?v=${version}`, () => {
|
||||
crossStorage.getRoteData({ userId }, resp => {
|
||||
resolve(resp);
|
||||
});
|
||||
|
||||
//分页数据默认条数
|
||||
const customPageCount = localStorage.getItem("customPageCount");
|
||||
crossStorage.getItem("customPageCount", resp => {
|
||||
if (resp == null) return false;
|
||||
if (customPageCount == null) localStorage.setItem("customPageCount", resp);
|
||||
else if (resp != customPageCount) {
|
||||
crossStorage.setItem({
|
||||
key: "customPageCount",
|
||||
value: customPageCount,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
HEAD.appendChild(node);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
console.error("获取身份信息失败!");
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
},
|
||||
layoutInit(info, mod, appList, baseHost, ssoHost) {
|
||||
this.layoutData.appName = "班级管理";
|
||||
this.layoutData.baseHost = baseHost;
|
||||
this.layoutData.ssoHost = ssoHost;
|
||||
const routes = this.$router.options.routes;
|
||||
let arr = [];
|
||||
mod.forEach(element => {
|
||||
let iconIndex = routes.findIndex(
|
||||
x =>
|
||||
typeof x.meta !== "undefined" &&
|
||||
typeof x.meta.modId !== "undefined" &&
|
||||
typeof x.meta.icon !== "undefined" &&
|
||||
x.meta.modId == element.modId
|
||||
);
|
||||
let icon = iconIndex > -1 ? "iconfont " + routes[iconIndex].meta.icon : ""; //icon不传则为默认
|
||||
arr.push({
|
||||
id: element.id,
|
||||
name: element.name,
|
||||
modId: element.modId,
|
||||
page: element.page,
|
||||
children: element.children || [],
|
||||
icon,
|
||||
});
|
||||
});
|
||||
// arr[0].icon = "iconfont icon-apps"; //icon样式示例,参见static/style/font 目录
|
||||
this.layoutData.modList = arr.sort((a, b) => a.modId - b.modId);
|
||||
this.layoutData.isAlone = arr.length == 1; //当只有一个选项卡时,隐藏menu和nav
|
||||
let { id, name, profilePicture } = info;
|
||||
this.layoutData.userInfo = { id, name, avatar: profilePicture };
|
||||
this.layoutData.appList = appList || [];
|
||||
//无权限
|
||||
if (arr.length == 0) {
|
||||
this.layoutData.isAlone = true;
|
||||
this.isNoAuthority = true;
|
||||
}
|
||||
},
|
||||
setCurrentRole(result, baseHost, userId) {
|
||||
if (result) {
|
||||
let { childId, roleId, schId } = result.checkRole;
|
||||
localStorage.setItem("currentRole", encodeURI(JSON.stringify({ childId, roleId, schId, userId })));
|
||||
localStorage.setItem("themeVersion", result.themeVersion);
|
||||
appendLink(baseHost, result.themeName, result.themeVersion);
|
||||
} else {
|
||||
appendLink(baseHost, "default-theme", new Date().getTime());
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
#loging-box,
|
||||
.mop-load-div {
|
||||
display: none;
|
||||
}
|
||||
/* 开始过渡阶段,动画出去阶段 */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: all 1ms cubic-bezier(0, 0.99, 1, 0.03);
|
||||
}
|
||||
/* 进入开始 */
|
||||
.fade-enter {
|
||||
// transform: translateY(10px);
|
||||
opacity: 0;
|
||||
}
|
||||
/* 出去终点 */
|
||||
.fade-leave-active {
|
||||
// transform: translateY(-10px);
|
||||
// opacity: 0;
|
||||
}
|
||||
|
||||
.back-enter-active,
|
||||
.back-leave-active {
|
||||
transition: all 1ms cubic-bezier(0, 0.99, 1, 0.03);
|
||||
}
|
||||
/* 进入开始 */
|
||||
.back-enter {
|
||||
display: none;
|
||||
}
|
||||
/* 出去终点 */
|
||||
.back-leave-active {
|
||||
display: none;
|
||||
}
|
||||
#app {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,198 @@
|
||||
// 配置API接口地址
|
||||
// var root = '/api/v1'
|
||||
// var root = '/api/debugapi'
|
||||
var root = "/api";
|
||||
// var root = ''
|
||||
// 引用axios
|
||||
var axios = require("axios");
|
||||
|
||||
// import Notice from 'iview/src/components/notice';
|
||||
import { Message } from "view-design";
|
||||
|
||||
// 自定义判断元素类型JS
|
||||
function toType(obj) {
|
||||
return {}.toString
|
||||
.call(obj)
|
||||
.match(/\s([a-zA-Z]+)/)[1]
|
||||
.toLowerCase();
|
||||
}
|
||||
// 参数过滤函数
|
||||
function filterNull(o) {
|
||||
for (var key in o) {
|
||||
if (o[key] === null) {
|
||||
delete o[key];
|
||||
}
|
||||
if (toType(o[key]) === "string") {
|
||||
o[key] = o[key].trim();
|
||||
} else if (toType(o[key]) === "object") {
|
||||
o[key] = filterNull(o[key]);
|
||||
} else if (toType(o[key]) === "array") {
|
||||
o[key] = filterNull(o[key]);
|
||||
}
|
||||
}
|
||||
return o;
|
||||
}
|
||||
/*
|
||||
接口处理函数
|
||||
这个函数每个项目都是不一样的,我现在调整的是适用于
|
||||
https://cnodejs.org/api/v1 的接口,如果是其他接口
|
||||
需要根据接口的参数进行调整。参考说明文档地址:
|
||||
https://cnodejs.org/topic/5378720ed6e2d16149fa16bd
|
||||
主要是,不同的接口的成功标识和失败提示是不一致的。
|
||||
另外,不同的项目的处理方法也是不一致的,这里出错就是简单的alert
|
||||
*/
|
||||
|
||||
function apiAxios(method, url, params, success, failure) {
|
||||
let conentTypeIsJosn = false;
|
||||
if (params && typeof params != "string") {
|
||||
params = filterNull(params);
|
||||
} else conentTypeIsJosn = true;
|
||||
|
||||
// if (!window.location.origin) {
|
||||
// window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
|
||||
// }
|
||||
// let redirectUrl=window.location.origin + window.location.hash.replace('#','/xiaoxi/#');
|
||||
|
||||
// console.log(window.location);
|
||||
|
||||
axios({
|
||||
method: method,
|
||||
url: url,
|
||||
data: method === "POST" || method === "PUT" ? params : null,
|
||||
params: method === "GET" || method === "DELETE" ? params : null,
|
||||
baseURL: root,
|
||||
withCredentials: true,
|
||||
crossDomain: true,
|
||||
transformRequest: [
|
||||
function (data) {
|
||||
// Do whatever you want to transform the data
|
||||
if (conentTypeIsJosn) return data;
|
||||
let ret = "";
|
||||
for (let it in data) {
|
||||
ret += encodeURIComponent(it) + "=" + encodeURIComponent(data[it]) + "&";
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
],
|
||||
headers: {
|
||||
// 'Content-Type': 'application/x-www-form-urlencoded',
|
||||
"Content-Type": conentTypeIsJosn ? "application/json" : "application/x-www-form-urlencoded",
|
||||
// bschapirequest: 1,
|
||||
yschapirequest:1,
|
||||
yschreferer: this.$utils.strToHexCharCode(window.location.href),
|
||||
},
|
||||
})
|
||||
.then(function (res) {
|
||||
let response = res.data;
|
||||
if (response.code == 302) {
|
||||
window.location.href = response.urlToRedirectTo;
|
||||
return;
|
||||
} else if (response.code == 0) {
|
||||
if (success) {
|
||||
success(response);
|
||||
}
|
||||
}else if (response.code == 4) {
|
||||
Message.error(response.msg); //错误处理
|
||||
} else {
|
||||
if (failure) {
|
||||
failure(response);
|
||||
} else {
|
||||
if (response.data == 2) {
|
||||
Message.error(response.msg); //错误处理
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 1000);
|
||||
} else {
|
||||
Message.info(response.msg); //错误处理
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
let res = err.response;
|
||||
console.error(res || err);
|
||||
if (res) {
|
||||
Message.destroy();
|
||||
clearTimeout(tiemObj);
|
||||
if (res.data.msg) {
|
||||
Message.error(res.data.msg); //错误处理
|
||||
} else {
|
||||
Message.error("网络请求出错"); //错误处理
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//字符串的16进制表达
|
||||
function strToHexCharCode(_str) {
|
||||
if (_str === "") return "";
|
||||
var hexCharCode = [];
|
||||
for (var i = 0; i < _str.length; i++) {
|
||||
var str = _str.charCodeAt(i).toString(16);
|
||||
if (_str.length == 1) str += "0" + _str;
|
||||
hexCharCode.push(str);
|
||||
}
|
||||
return hexCharCode.join("");
|
||||
}
|
||||
|
||||
let requestCount = 0,
|
||||
tiemObj;
|
||||
// http request 拦截器
|
||||
axios.interceptors.request.use(config => {
|
||||
requestCount++;
|
||||
if (requestCount == 1) {
|
||||
tiemObj = setTimeout(() => {
|
||||
Message.loading({ content: "加载中...", duration: 0 });
|
||||
}, 800);
|
||||
}
|
||||
// if (localStorage.getItem("currentRole"))
|
||||
// config.headers["currentRole"] = localStorage.getItem("currentRole");
|
||||
if (localStorage.getItem("currentRole")) {
|
||||
let currentRole = localStorage.getItem("currentRole");
|
||||
config.headers["currentrole"] = currentRole;
|
||||
let { schId, roleId, userId, childId } = JSON.parse(decodeURIComponent(currentRole));
|
||||
// config.headers["schoolId"] = schId;
|
||||
// config.headers["userId"] = userId;
|
||||
// config.headers["roleId"] = roleId;
|
||||
if (roleId == 3) {
|
||||
config.headers["userId"] = childId;
|
||||
}
|
||||
sessionStorage.setItem("userId",userId);
|
||||
}
|
||||
if(sessionStorage.getItem("uType")){
|
||||
config.headers["uType"] = sessionStorage.getItem("uType");
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
||||
// http response 拦截器
|
||||
axios.interceptors.response.use(response => {
|
||||
requestCount--;
|
||||
if (requestCount === 0) {
|
||||
setTimeout(() => {
|
||||
Message.destroy();
|
||||
}, 1500);
|
||||
clearTimeout(tiemObj);
|
||||
}
|
||||
return response;
|
||||
});
|
||||
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
// axios.defaults.headers.post['Content-Type'] = 'application/json; charset=utf-8';
|
||||
// axios.defaults.withCredentials = true
|
||||
|
||||
// 返回在vue模板中的调用接口
|
||||
export default {
|
||||
get: function (url, params, success, failure) {
|
||||
return apiAxios("GET", url, params, success, failure);
|
||||
},
|
||||
post: function (url, params, success, failure) {
|
||||
return apiAxios("POST", url, params, success, failure);
|
||||
},
|
||||
put: function (url, params, success, failure) {
|
||||
return apiAxios("PUT", url, params, success, failure);
|
||||
},
|
||||
delete: function (url, params, success, failure) {
|
||||
return apiAxios("DELETE", url, params, success, failure);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,180 @@
|
||||
// 配置API接口地址
|
||||
// var root = '/api/v1'
|
||||
// var root = '/api/debugapi'
|
||||
var root = "/api";
|
||||
// var root = ''
|
||||
// 引用axios
|
||||
var axios = require("axios");
|
||||
|
||||
// import Notice from 'iview/src/components/notice';
|
||||
import { Message } from "view-design";
|
||||
|
||||
// 自定义判断元素类型JS
|
||||
function toType(obj) {
|
||||
return {}.toString
|
||||
.call(obj)
|
||||
.match(/\s([a-zA-Z]+)/)[1]
|
||||
.toLowerCase();
|
||||
}
|
||||
// 参数过滤函数
|
||||
function filterNull(o) {
|
||||
for (var key in o) {
|
||||
if (o[key] === null) {
|
||||
delete o[key];
|
||||
}
|
||||
if (toType(o[key]) === "string") {
|
||||
o[key] = o[key].trim();
|
||||
} else if (toType(o[key]) === "object") {
|
||||
o[key] = filterNull(o[key]);
|
||||
} else if (toType(o[key]) === "array") {
|
||||
o[key] = filterNull(o[key]);
|
||||
}
|
||||
}
|
||||
return o;
|
||||
}
|
||||
/*
|
||||
接口处理函数
|
||||
这个函数每个项目都是不一样的,我现在调整的是适用于
|
||||
https://cnodejs.org/api/v1 的接口,如果是其他接口
|
||||
需要根据接口的参数进行调整。参考说明文档地址:
|
||||
https://cnodejs.org/topic/5378720ed6e2d16149fa16bd
|
||||
主要是,不同的接口的成功标识和失败提示是不一致的。
|
||||
另外,不同的项目的处理方法也是不一致的,这里出错就是简单的alert
|
||||
*/
|
||||
|
||||
function apiAxios(method, url, params, success, failure) {
|
||||
let conentTypeIsJosn = false;
|
||||
if (params && typeof params != "string") {
|
||||
params = filterNull(params);
|
||||
} else conentTypeIsJosn = true;
|
||||
|
||||
// if (!window.location.origin) {
|
||||
// window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
|
||||
// }
|
||||
// let redirectUrl=window.location.origin + window.location.hash.replace('#','/xiaoxi/#');
|
||||
|
||||
// console.log(window.location);
|
||||
|
||||
axios({
|
||||
method: method,
|
||||
url: url,
|
||||
data: method === "POST" || method === "PUT" ? params : null,
|
||||
params: method === "GET" || method === "DELETE" ? params : null,
|
||||
baseURL: root,
|
||||
// withCredentials: true,
|
||||
crossDomain: true,
|
||||
transformRequest: [
|
||||
function(data) {
|
||||
// Do whatever you want to transform the data
|
||||
if (conentTypeIsJosn) return data;
|
||||
let ret = "";
|
||||
for (let it in data) {
|
||||
ret +=
|
||||
encodeURIComponent(it) + "=" + encodeURIComponent(data[it]) + "&";
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
],
|
||||
headers: {
|
||||
// 'Content-Type': 'application/x-www-form-urlencoded',
|
||||
"Content-Type": conentTypeIsJosn
|
||||
? "application/json"
|
||||
: "application/x-www-form-urlencoded",
|
||||
},
|
||||
})
|
||||
.then(function(res) {
|
||||
let response = res.data;
|
||||
if (response.State) {
|
||||
if (success) {
|
||||
success(response);
|
||||
}
|
||||
} else {
|
||||
if (failure) {
|
||||
failure(response.Data);
|
||||
} else {
|
||||
if (response.Data == 2) {
|
||||
Message.error(response.Message); //错误处理
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 1000);
|
||||
} else {
|
||||
Message.info(response.Message); //错误处理
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
let res = err.response;
|
||||
console.error(res || err);
|
||||
if (res) {
|
||||
Message.destroy();
|
||||
clearTimeout(tiemObj);
|
||||
// if(res.status===401&&res.data.OtherData.ErrorCode==2){
|
||||
if (res.status === 401) {
|
||||
window.location.reload();
|
||||
// if(process.env.NODE_ENV === 'production')
|
||||
// Message.error(res.data.Message);//错误处理
|
||||
// setTimeout(() => {
|
||||
// location.reload();
|
||||
// }, 0);
|
||||
} else if (res.data.Message) {
|
||||
Message.error(res.data.Message); //错误处理
|
||||
} else {
|
||||
Message.error("网络请求出错"); //错误处理
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let requestCount = 0,
|
||||
tiemObj;
|
||||
// http request 拦截器
|
||||
axios.interceptors.request.use((config) => {
|
||||
requestCount++;
|
||||
if (requestCount == 1) {
|
||||
tiemObj = setTimeout(() => {
|
||||
Message.loading({ content: "加载中...", duration: 0 });
|
||||
}, 800);
|
||||
}
|
||||
if (localStorage.getItem("currentRole"))
|
||||
config.headers["currentRole"] = localStorage.getItem("currentRole");
|
||||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
//如果是开发环境
|
||||
config.headers["DebugUser"] = "zhd";
|
||||
config.headers["DebugAppType"] = true;
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
||||
// http response 拦截器
|
||||
axios.interceptors.response.use((response) => {
|
||||
requestCount--;
|
||||
if (requestCount === 0) {
|
||||
setTimeout(() => {
|
||||
Message.destroy();
|
||||
}, 1500);
|
||||
clearTimeout(tiemObj);
|
||||
}
|
||||
return response;
|
||||
});
|
||||
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
// axios.defaults.headers.post['Content-Type'] = 'application/json; charset=utf-8';
|
||||
// axios.defaults.withCredentials = true
|
||||
|
||||
// 返回在vue模板中的调用接口
|
||||
export default {
|
||||
get: function(url, params, success, failure) {
|
||||
return apiAxios("GET", url, params, success, failure);
|
||||
},
|
||||
post: function(url, params, success, failure) {
|
||||
return apiAxios("POST", url, params, success, failure);
|
||||
},
|
||||
put: function(url, params, success, failure) {
|
||||
return apiAxios("PUT", url, params, success, failure);
|
||||
},
|
||||
delete: function(url, params, success, failure) {
|
||||
return apiAxios("DELETE", url, params, success, failure);
|
||||
},
|
||||
};
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,59 @@
|
||||
var HtmlUtil = {
|
||||
/*1.用浏览器内部转换器实现html转码*/
|
||||
htmlEncode: function(html) {
|
||||
//1.首先动态创建一个容器标签元素,如DIV
|
||||
var temp = document.createElement("div");
|
||||
//2.然后将要转换的字符串设置为这个元素的innerText(ie支持)或者textContent(火狐,google支持)
|
||||
temp.textContent != undefined ? (temp.textContent = html) : (temp.innerText = html);
|
||||
//3.最后返回这个元素的innerHTML,即得到经过HTML编码转换的字符串了
|
||||
var output = temp.innerHTML;
|
||||
temp = null;
|
||||
return output;
|
||||
},
|
||||
/*2.用浏览器内部转换器实现html解码*/
|
||||
htmlDecode: function(text) {
|
||||
//1.首先动态创建一个容器标签元素,如DIV
|
||||
var temp = document.createElement("div");
|
||||
//2.然后将要转换的字符串设置为这个元素的innerHTML(ie,火狐,google都支持)
|
||||
temp.innerHTML = text;
|
||||
//3.最后返回这个元素的innerText(ie支持)或者textContent(火狐,google支持),即得到经过HTML解码的字符串了。
|
||||
var output = temp.innerText || temp.textContent;
|
||||
temp = null;
|
||||
return output;
|
||||
},
|
||||
/*3.用正则表达式实现html转码*/
|
||||
htmlEncodeByRegExp: function(str) {
|
||||
var s = "";
|
||||
if (str.length == 0) return "";
|
||||
s = str.replace(/&/g, "&");
|
||||
s = s.replace(/</g, "<");
|
||||
s = s.replace(/>/g, ">");
|
||||
s = s.replace(/ /g, " ");
|
||||
s = s.replace(/\'/g, "'");
|
||||
s = s.replace(/\"/g, """);
|
||||
return s;
|
||||
},
|
||||
/*4.用正则表达式实现html解码*/
|
||||
htmlDecodeByRegExp: function(str) {
|
||||
var s = "";
|
||||
if (str.length == 0) return "";
|
||||
s = str.replace(/&/g, "&");
|
||||
s = s.replace(/</g, "<");
|
||||
s = s.replace(/>/g, ">");
|
||||
s = s.replace(/ /g, " ");
|
||||
s = s.replace(/'/g, "'");
|
||||
s = s.replace(/"/g, '"');
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
export const load = name => {
|
||||
let url = (process.env.NODE_ENV === "production" ? "/SchConfig/standard" : "") + "/code/" + name;
|
||||
// let url = "../code/" + name;
|
||||
return new Promise((resolve, reject) => {
|
||||
$.get(url, resp => {
|
||||
let encode = HtmlUtil.htmlEncode(resp);
|
||||
resolve({ html: resp, encode });
|
||||
});
|
||||
});
|
||||
};
|
||||
Vendored
+22
File diff suppressed because one or more lines are too long
Vendored
+27
File diff suppressed because one or more lines are too long
Vendored
+4
File diff suppressed because one or more lines are too long
@@ -0,0 +1,97 @@
|
||||
ol,p,h1,h2,h3,h4,h5,ul,dd,dt,ol{padding:0px;margin:0px;list-style:none}
|
||||
html{-webkit-text-size-adjust:none}
|
||||
body{width:100%;margin:0;padding:0;position:relative;height:100%;color:#333;min-width:1200px}
|
||||
html,body,#app{margin:0;padding:0;height:100%;font-size:14px;}
|
||||
a{
|
||||
text-decoration:none;-webkit-tap-highlight-color:transparent;outline:none;
|
||||
&:hover,&:active{text-decoration:none}
|
||||
}
|
||||
*{border:0;margin:0;padding:0;box-sizing:border-box;font-family:'PingFang SC',tahoma,arial,'helvetica neue','hiragino sans gb','microsoft yahei',sans-serif}
|
||||
|
||||
|
||||
|
||||
//搜索框
|
||||
.search-wrap {
|
||||
background: #f7f7f7;
|
||||
padding: 15px;
|
||||
&_date {
|
||||
.ivu-date-picker {
|
||||
width: 150px;
|
||||
}
|
||||
}
|
||||
&_sel{
|
||||
width:150px;
|
||||
float: left;
|
||||
}
|
||||
&_input{
|
||||
width:200px;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
.public {
|
||||
&-custom-switch {
|
||||
.ivu-radio-wrapper-checked {
|
||||
background: #6b8cf4 !important;
|
||||
border-color: #6b8cf4 !important;
|
||||
}
|
||||
.ivu-radio-group-item {
|
||||
width: 90px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
&-upload-img {
|
||||
li {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 2px;
|
||||
padding: 4px;
|
||||
position: relative;
|
||||
float: left;
|
||||
margin: 0 10px 10px 0;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
&:hover .upload-list-cover {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.upload-list-cover {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
bottom: 4px;
|
||||
left: 4px;
|
||||
right: 4px;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
text-align: center;
|
||||
display: none;
|
||||
transition: all 0.3s;
|
||||
|
||||
i {
|
||||
color: #fff;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
cursor: pointer;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
li.add-li {
|
||||
border: none;
|
||||
padding: 0;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
li .add-box i {
|
||||
line-height: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block;}audio,canvas,video{display:inline-block;}audio:not([controls]){display:none;height:0;}[hidden]{display:none;}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;}body{margin:0;}a:focus{outline:thin dotted;}a:active,a:hover{outline:0;}h1{font-size:2em;margin:0.67em 0;}abbr[title]{border-bottom:1px dotted;}b,strong{font-weight:bold;}dfn{font-style:italic;}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0;}mark{background:#ff0;color:#000;}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em;}pre{white-space:pre-wrap;}q{quotes:"\201C" "\201D" "\2018" "\2019";}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sup{top:-0.5em;}sub{bottom:-0.25em;}img{border:0;}svg:not(:root){overflow:hidden;}figure{margin:0;}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em;}legend{border:0;padding:0;}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0;}button,input{line-height:normal;}button,select{text-transform:none;}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}button[disabled],html input[disabled]{cursor:default;}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}textarea{overflow:auto;vertical-align:top;}table{border-collapse:collapse;border-spacing:0;}
|
||||
@@ -0,0 +1,161 @@
|
||||
.f10 {
|
||||
font-size: 10px;
|
||||
}
|
||||
.f12 {
|
||||
font-size: 12px;
|
||||
}
|
||||
.f13 {
|
||||
font-size: 13px;
|
||||
}
|
||||
.f14 {
|
||||
font-size: 14px;
|
||||
}
|
||||
.f15 {
|
||||
font-size: 15px;
|
||||
}
|
||||
.f16 {
|
||||
font-size: 16px;
|
||||
}
|
||||
.f17 {
|
||||
font-size: 17px;
|
||||
}
|
||||
.f18 {
|
||||
font-size: 18px;
|
||||
}
|
||||
.f20 {
|
||||
font-size: 20px;
|
||||
}
|
||||
.f24 {
|
||||
font-size: 24px;
|
||||
}
|
||||
// 文字对齐
|
||||
.tl {
|
||||
text-align: left;
|
||||
}
|
||||
.tc {
|
||||
text-align: center;
|
||||
}
|
||||
.tr {
|
||||
text-align: right;
|
||||
}
|
||||
//浮动
|
||||
.fr {
|
||||
float: right !important;
|
||||
}
|
||||
.fl {
|
||||
float: left !important;
|
||||
}
|
||||
.fix {
|
||||
*zoom: 1;
|
||||
}
|
||||
.fix:after {
|
||||
display: table;
|
||||
content: "";
|
||||
clear: both;
|
||||
}
|
||||
.clearfix {
|
||||
@extend .fix;
|
||||
}
|
||||
// 显示
|
||||
.dn {
|
||||
display: none;
|
||||
}
|
||||
.di {
|
||||
display: inline;
|
||||
}
|
||||
.db {
|
||||
display: block;
|
||||
}
|
||||
.dib {
|
||||
display: inline-block;
|
||||
}
|
||||
.dt {
|
||||
display: table;
|
||||
}
|
||||
div.dib {
|
||||
*display: inline;
|
||||
*zoom: 1;
|
||||
}
|
||||
.vm {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.vib {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
// 定位
|
||||
.pr {
|
||||
position: relative;
|
||||
}
|
||||
.pa {
|
||||
position: absolute;
|
||||
}
|
||||
.pf {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.oh {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@for $i from 1 through 100 {
|
||||
.width-#{$i} {
|
||||
width: $i * 1px;
|
||||
}
|
||||
.height-#{$i} {
|
||||
height: $i * 1px;
|
||||
}
|
||||
.ml-#{$i} {
|
||||
margin-left: $i * 1px;
|
||||
}
|
||||
.mr-#{$i} {
|
||||
margin-right: $i * 1px;
|
||||
}
|
||||
.mt-#{$i} {
|
||||
margin-top: $i * 1px;
|
||||
}
|
||||
.mb-#{$i} {
|
||||
margin-bottom: $i * 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.align-middle {
|
||||
position: relative;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
.align-middle-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
//0.5px
|
||||
@mixin border(
|
||||
$borderWidth: 1px,
|
||||
$borderStyle: solid,
|
||||
$borderColor: #ddd,
|
||||
$borderRadius: 0
|
||||
) {
|
||||
position: relative;
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
transform-origin: left top;
|
||||
-webkit-transform-origin: left top;
|
||||
-webkit-transform: scale(0.5);
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&:before {
|
||||
border-width: $borderWidth;
|
||||
border-style: $borderStyle;
|
||||
border-color: $borderColor;
|
||||
border-radius: $borderRadius;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*滚动条样式 */
|
||||
|
||||
/*第一种样式,所有的滚动条,都默认这个样子*/
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
/*正常情况下滑块的样式*/
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, .05);
|
||||
border-radius: 10px;
|
||||
-webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
/*鼠标悬浮在该类指向的控件上时滑块的样式*/
|
||||
*:hover::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, .2);
|
||||
border-radius: 10px;
|
||||
-webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
/*鼠标悬浮在滑块上时滑块的样式*/
|
||||
*::-webkit-scrollbar-thumb:hover {
|
||||
background-color: rgba(0, 0, 0, .3);
|
||||
-webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
/*正常时候的主干部分*/
|
||||
*::-webkit-scrollbar-track {
|
||||
border-radius: 10px;
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
/*鼠标悬浮在滚动条上的主干部分*/
|
||||
*::-webkit-scrollbar-track:hover {
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .4);
|
||||
background-color: rgba(0, 0, 0, .01);
|
||||
}
|
||||
|
||||
/*第一种样式结束*/
|
||||
|
||||
|
||||
/*第二种样式*/
|
||||
|
||||
.scroll2::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
/*正常时候的主干部分*/
|
||||
.scroll2::-webkit-scrollbar-track {
|
||||
border-radius: 10px;
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
/*正常情况下滑块的样式*/
|
||||
.scroll2::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, .05);
|
||||
border-radius: 10px;
|
||||
-webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
/*鼠标悬浮在该类指向的控件上时滑块的样式*/
|
||||
.scroll2:hover::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, .2);
|
||||
border-radius: 10px;
|
||||
-webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
/*鼠标悬浮在滚动条上的主干部分*/
|
||||
.scroll2::-webkit-scrollbar-track:hover {
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .4);
|
||||
}
|
||||
|
||||
/*鼠标悬浮在滑块上时滑块的样式*/
|
||||
.scroll2::-webkit-scrollbar-thumb:hover {
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .4);
|
||||
}
|
||||
|
||||
/*第二种样式结束*/
|
||||
@@ -0,0 +1,31 @@
|
||||
@import "base";
|
||||
@import "normalize";
|
||||
@import "utils";
|
||||
@import "bscroll.css";
|
||||
// @import "iview_override";
|
||||
|
||||
.webapp-panel{
|
||||
background: url(../image/phone.png) no-repeat;
|
||||
width: 337px;
|
||||
height: 580px;
|
||||
padding: 50px 35px 60px 35px;
|
||||
}
|
||||
.ivu-tree-arrow .ivu-icon-ios-arrow-forward:before {
|
||||
content: "\e65c"; /* 例如,使用阿里巴巴矢量图标库的某个图标 */
|
||||
font-family: "iconfont"; /* 替换为你的图标字体 */
|
||||
color: #8e9397;
|
||||
}
|
||||
.ivu-tree-arrow-open .ivu-icon-ios-arrow-forward:before {
|
||||
content: "\e65d"; /* 例如,使用阿里巴巴矢量图标库的某个图标 */
|
||||
font-family: "iconfont"; /* 替换为你的图标字体 */
|
||||
color: #8e9397;
|
||||
}
|
||||
.ivu-tree-arrow-open i{
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1366px) {
|
||||
html {
|
||||
zoom: 0.9;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,473 @@
|
||||
$tabBtnColor: #577ae9;//tab主题色
|
||||
$treeCheckColor: #577ae9;//树主题色
|
||||
$treeCheckBorderColor: #dddee1;//边框色
|
||||
$treeCheckGroupColor: #f7f7f7;
|
||||
|
||||
.fix {
|
||||
*zoom: 1;
|
||||
&::before,
|
||||
&::after {
|
||||
display: table;
|
||||
content: "";
|
||||
line-height: 0;
|
||||
}
|
||||
&::after {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
.fl {
|
||||
float: left;
|
||||
}
|
||||
.fr {
|
||||
float: right;
|
||||
}
|
||||
.align-middle {
|
||||
position: relative;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.my-tab_btn {
|
||||
margin: 10px auto;
|
||||
position: relative;
|
||||
.item-tab_btn {
|
||||
font-size: 16px;
|
||||
font-weight: 550;
|
||||
color: #656667;
|
||||
float: left;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.item-tab_btn.active {
|
||||
color: #272829;
|
||||
}
|
||||
|
||||
.my-tab_slider {
|
||||
width: 42px;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: -1px;
|
||||
z-index: 1;
|
||||
transition: transform 0.3s ease-in-out;
|
||||
transform-origin: 0 0;
|
||||
& > .indicator {
|
||||
height: 2px;
|
||||
width: 17px;
|
||||
background: $tabBtnColor;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.my-tab_card {
|
||||
margin: 15px 0 15px 10px;
|
||||
padding-right: 30px;
|
||||
position: relative;
|
||||
.item-wrap{
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
.item-tab_card {
|
||||
float: left;
|
||||
font-size: 13px;
|
||||
padding: 0px 15px;
|
||||
color: #808080;
|
||||
height: 27px;
|
||||
line-height: 27px;
|
||||
transition: all 200ms;
|
||||
}
|
||||
.item-tab_card.active {
|
||||
color: #272829;
|
||||
background: #f7f7f7;
|
||||
border-radius: 27px;
|
||||
}
|
||||
}
|
||||
|
||||
.my-modal {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.5;
|
||||
background: #000;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.tree-popup {
|
||||
position: fixed;
|
||||
background: #fff;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
transform: translateY(0);
|
||||
backface-visibility: hidden;
|
||||
transition: 0.2s ease-in;
|
||||
width: 100%;
|
||||
height: 85%;
|
||||
z-index: 101;
|
||||
border-radius: 8px 8px 0 0;
|
||||
&_show {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
&_hide {
|
||||
transform: translateY(0%);
|
||||
}
|
||||
|
||||
&_header {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
@extend .my-border_bottom;
|
||||
|
||||
& .close-btn {
|
||||
position: absolute;
|
||||
padding: 5px;
|
||||
right: 3%;
|
||||
top: 10px;
|
||||
}
|
||||
}
|
||||
&_body {
|
||||
overflow-y: auto;
|
||||
min-height: 250px;
|
||||
}
|
||||
|
||||
&_footer {
|
||||
height: 60px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
padding: 0 10px 0 20px;
|
||||
@extend .my-border_top;
|
||||
.check-box {
|
||||
float: left;
|
||||
&_text {
|
||||
margin-left: 3px;
|
||||
margin-right: 30px;
|
||||
vertical-align: middle;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
& p {
|
||||
font-size: 16px;
|
||||
color: #808080;
|
||||
|
||||
span {
|
||||
font-size: 18px;
|
||||
color: $treeCheckColor;
|
||||
}
|
||||
}
|
||||
& button {
|
||||
width: 80px;
|
||||
height: 40px;
|
||||
color: #fff;
|
||||
background: $treeCheckColor;
|
||||
border-radius: 5px;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-list {
|
||||
background: #f7f7f7;
|
||||
height: calc(100% - 46px);
|
||||
margin-top:46px;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
.search-head {
|
||||
height: 46px;
|
||||
line-height: 46px;
|
||||
padding: 0 10px 0 15px;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
box-sizing: border-box;
|
||||
background: #f7f7f7;
|
||||
input {
|
||||
background: #efefef;
|
||||
-webkit-appearance: none;
|
||||
outline: none;
|
||||
width: calc(100% - 70px);
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0 15px;
|
||||
border-radius: 28px;
|
||||
font-size: 14px;
|
||||
&::-webkit-input-placeholder {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
span {
|
||||
margin-left: 5px;
|
||||
color: #272829;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
width: 18px;
|
||||
line-height: 18px;
|
||||
height: 18px;
|
||||
position: absolute;
|
||||
right: 60px;
|
||||
top: 15px;
|
||||
}
|
||||
}
|
||||
.search-item {
|
||||
background: #fff;
|
||||
height: 46px;
|
||||
line-height: 46px;
|
||||
padding-left: 12px;
|
||||
a {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
color: #333;
|
||||
outline: none;
|
||||
@extend .my-border_bottom;
|
||||
}
|
||||
&_text {
|
||||
margin-left: 2px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
&_group {
|
||||
float: right;
|
||||
color: #808080;
|
||||
font-size: 12px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-popup {
|
||||
position: fixed;
|
||||
background: #fff;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
transform: translateY(0);
|
||||
backface-visibility: hidden;
|
||||
transition: 0.2s ease-in;
|
||||
width: 100%;
|
||||
height: 75%;
|
||||
z-index: 105;
|
||||
border-radius: 8px 8px 0 0;
|
||||
&_show {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
&_hide {
|
||||
transform: translateY(0%);
|
||||
}
|
||||
&_header {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
@extend .my-border_bottom;
|
||||
h4 {
|
||||
font-size: 18px;
|
||||
margin: 12px 0 5px;
|
||||
color: #272829;
|
||||
text-align: center;
|
||||
}
|
||||
h6 {
|
||||
color: #595959;
|
||||
font-size: 13px;
|
||||
margin: 5px 0 15px;
|
||||
text-align: center;
|
||||
}
|
||||
& .close-btn {
|
||||
position: absolute;
|
||||
padding: 5px;
|
||||
right: 3%;
|
||||
top: 10px;
|
||||
}
|
||||
}
|
||||
&_body {
|
||||
overflow-y: auto;
|
||||
height: calc(100% - 70px);
|
||||
padding: 12px 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
&_ul {
|
||||
@extend .fix;
|
||||
li {
|
||||
background: #f4f8ff;
|
||||
float: left;
|
||||
margin: 4px;
|
||||
width: calc(33.333% - 8px);
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
h4,
|
||||
h6 {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
h4 {
|
||||
font-size: 16px;
|
||||
margin: 6px 0;
|
||||
color: #272829;
|
||||
text-align: center;
|
||||
}
|
||||
h6 {
|
||||
color: #595959;
|
||||
font-size: 12px;
|
||||
height: 16px;
|
||||
margin: 6px 0;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-box {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
box-sizing: border-box;
|
||||
padding: 2px;
|
||||
top: 2px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.bg-arrow_grey {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAABE0lEQVRYR+3VMQ6CMBQG4PdImPUIHsEjeBRZCJ30KDqVsNSjeASPwBF0Y6KmiSQM0NfXdiDmsZDQ0n79Wx4IG7twYx4QELUjkpAkRCVAtcsZ+p+EjDH7YRj2SqmeWhWnveu6Y1mWfVVV76X3Vs9Q27Y3RLyM41gppR6cSdf6aq3PRVEYa+29aZorC+RWYq19AsAuB2rCAMAHEU91Xb9YINc5FyoU4+YkP/tUFAcTBEpJiosJBsWgYjAsEAcVi2GDQlApmCiQD5WKiQYtodwzV/SoOkMVWPKz9w0wLwm/ft6iR2GSEpoGn6HAV4FDMFlAbhCt9cHdc/yIk7YsdNWcfgKi0pKEJCEqAapdzpAkRCVAtX8BqXjGJWAVZBoAAAAASUVORK5CYII=");
|
||||
background-repeat: no-repeat;
|
||||
display: inline-block;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
zoom: 0.3;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.conta-wrap {
|
||||
position: relative;
|
||||
.tree-item {
|
||||
padding: 12px;
|
||||
color: #333;
|
||||
position: relative;
|
||||
a {
|
||||
color: #333;
|
||||
display: inline-block;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
input {
|
||||
display: none;
|
||||
}
|
||||
label {
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
margin-left: 2px;
|
||||
}
|
||||
&_group {
|
||||
background: $treeCheckGroupColor;
|
||||
@extend .my-border_bottom;
|
||||
}
|
||||
|
||||
&_arrow {
|
||||
&::before {
|
||||
@extend .bg-arrow_grey;
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 2%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto 0;
|
||||
transition: 300ms cubic-bezier(0.47, 0, 0.745, 0.715);
|
||||
}
|
||||
}
|
||||
&_open,
|
||||
&_close {
|
||||
@extend .tree-item_arrow;
|
||||
}
|
||||
&_close::before {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.my-checkbox-core {
|
||||
border-radius: 3px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: inline-block;
|
||||
background-color: #fff;
|
||||
border: 1px solid $treeCheckBorderColor;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.my-checkbox-core.active {
|
||||
background-color: $treeCheckColor;
|
||||
border-color: $treeCheckColor;
|
||||
&::after {
|
||||
border: 2px solid transparent;
|
||||
border-left: 0;
|
||||
border-top: 0;
|
||||
content: " ";
|
||||
top: 3px;
|
||||
left: 7px;
|
||||
position: absolute;
|
||||
width: 4px;
|
||||
height: 8px;
|
||||
-webkit-transform: rotate(45deg) scale(0);
|
||||
transform: rotate(45deg) scale(0);
|
||||
transition: -webkit-transform 0.2s;
|
||||
-webkit-transition: -webkit-transform 0.2s;
|
||||
transition: transform 0.2s;
|
||||
transition: transform 0.2s, -webkit-transform 0.2s;
|
||||
border-color: #fff;
|
||||
-webkit-transform: rotate(45deg) scale(1);
|
||||
transform: rotate(45deg) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.my-border_bottom::after {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
color: #d9d9d9;
|
||||
-webkit-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
border-bottom: 1px solid #d9d9d9;
|
||||
height: 1px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
-webkit-transform: scaleY(0.5);
|
||||
transform: scaleY(0.5);
|
||||
transition: 0;
|
||||
}
|
||||
|
||||
.my-border_top::after {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
color: #d9d9d9;
|
||||
-webkit-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
border-top: 1px solid #d9d9d9;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
-webkit-transform: scaleY(0.5);
|
||||
transform: scaleY(0.5);
|
||||
transition: 0;
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 300ms ease-in-out;
|
||||
}
|
||||
.fade-enter,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
@@ -0,0 +1,505 @@
|
||||
<template>
|
||||
<div>
|
||||
<div :id="domId" :class="['tree-popup', isPopupShow ? 'tree-popup_show' : 'tree-popup_hide']">
|
||||
<div class="tree-popup_header">
|
||||
<div class="my-tab_btn fix">
|
||||
<div
|
||||
:class="{
|
||||
'item-tab_btn': true,
|
||||
active: firstTabIndex == tindex,
|
||||
}"
|
||||
@click="tabBtnChange(tindex)"
|
||||
v-for="(titem, tindex) in firstTabData"
|
||||
>
|
||||
{{ titem }}
|
||||
</div>
|
||||
<div class="my-tab_slider" v-if="firstTabData.length > 0" :style="tabSliderStyle">
|
||||
<div class="indicator"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-tab_card fix" v-if="secondTabData.length > 1">
|
||||
<div class="item-wrap">
|
||||
<div
|
||||
:class="{
|
||||
'item-tab_card': true,
|
||||
active: secondTabIndex == tindex,
|
||||
}"
|
||||
@click="tabCardChange(tindex)"
|
||||
v-for="(titem, tindex) in secondTabData"
|
||||
>
|
||||
{{ titem }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-box" @click="isSearchShow = !isSearchShow">
|
||||
<svg t="1626398915347" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4152" width="16" height="16">
|
||||
<path
|
||||
d="M921.3 874L738.1 690.8c51.3-62.6 82.1-142.5 82.1-229.6 0-200.1-162.8-363-363-363-200.1 0-363 162.8-363 363s162.8 363 363 363c87 0 167-30.8 229.6-82.1L870 925.3c7.1 7.1 16.4 10.6 25.7 10.6s18.6-3.5 25.7-10.6c14.1-14.2 14.1-37.2-0.1-51.3zM166.8 461.2c0-160.1 130.3-290.4 290.4-290.4s290.4 130.3 290.4 290.4-130.3 290.4-290.4 290.4-290.4-130.3-290.4-290.4z"
|
||||
p-id="4153"
|
||||
fill="#808080"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="close-btn" @click="popupColse">
|
||||
<svg t="1626397122082" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3133" width="14" height="14">
|
||||
<path d="M877.216 491.808" p-id="3134" fill="#595959"></path>
|
||||
<path
|
||||
d="M575.328 510.496 946.784 140.672c17.568-17.504 17.664-45.824 0.192-63.424-17.504-17.632-45.792-17.664-63.36-0.192L512.032 446.944 143.712 77.216C126.304 59.712 97.92 59.648 80.384 77.12 62.848 94.624 62.816 123.008 80.288 140.576l368.224 369.632L77.216 879.808c-17.568 17.504-17.664 45.824-0.192 63.424 8.736 8.8 20.256 13.216 31.776 13.216 11.424 0 22.848-4.352 31.584-13.056l371.36-369.696 371.68 373.088C892.192 955.616 903.68 960 915.168 960c11.456 0 22.912-4.384 31.648-13.088 17.504-17.504 17.568-45.824 0.096-63.392L575.328 510.496 575.328 510.496zM575.328 510.496"
|
||||
p-id="3135"
|
||||
fill="#595959"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tree-popup_body">
|
||||
<tree v-if="!isSearchShow" :treeData="currentTree" :userids="tempUserIds"></tree>
|
||||
<div v-else class="search-list">
|
||||
<div class="search-head" :style="searchHeadStyle">
|
||||
<input type="text" placeholder="请输入关键字" v-model="searchText" />
|
||||
<div class="close-icon" v-show="searchText" @click="searchText = null">
|
||||
<svg t="1626484787749" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2043" width="18" height="18">
|
||||
<path
|
||||
d="M512 51.2C258.048 51.2 51.2 258.048 51.2 512s206.848 460.8 460.8 460.8 460.8-206.848 460.8-460.8S765.952 51.2 512 51.2z m181.248 612.352c8.192 8.192 8.192 20.48 0 28.672-4.096 4.096-9.216 6.144-14.336 6.144s-10.24-2.048-14.336-6.144L512 540.672 360.448 693.248c-4.096 4.096-9.216 6.144-14.336 6.144s-10.24-2.048-14.336-6.144c-8.192-8.192-8.192-20.48 0-28.672L483.328 512 330.752 360.448c-8.192-8.192-8.192-20.48 0-28.672s20.48-8.192 28.672 0L512 483.328l151.552-151.552c8.192-8.192 20.48-8.192 28.672 0s8.192 20.48 0 28.672L540.672 512l152.576 151.552z"
|
||||
p-id="2044"
|
||||
fill="#cccccc"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<span @click="isSearchShow = false">取消</span>
|
||||
</div>
|
||||
<div class="search-item" v-for="item in searchList">
|
||||
<a href="javascript:;" @click="checkTreeById(item.id, !item.isCheck)">
|
||||
<span :class="['my-checkbox-core', item.isCheck ? 'active' : '']"></span>
|
||||
<span class="search-item_text">{{ item.name }}</span>
|
||||
|
||||
<span class="search-item_group">{{ item.group }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tree-popup_footer fix">
|
||||
<div class="check-box align-middle" v-show="!isSearchShow">
|
||||
<label @click="saveAllCheck">
|
||||
<span :class="['my-checkbox-core', isAllTreeCheck ? 'active' : '']"></span>
|
||||
<span class="check-box_text">全选</span>
|
||||
</label>
|
||||
</div>
|
||||
<p class="fl align-middle" @click="isUserModalShow = true">
|
||||
已选人数:
|
||||
<span>{{ tempUserIds.length }}</span>
|
||||
</p>
|
||||
<button v-show="isSearchShow" class="fr align-middle" @click="isSearchShow = false">确认</button>
|
||||
<button v-show="!isSearchShow" class="fr align-middle" @click="submit">提交</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="isModalShow" class="my-modal" @click="popupColse"></div>
|
||||
<div :class="['user-popup', isUserModalShow ? 'user-popup_show' : 'user-popup_hide']">
|
||||
<div class="user-popup_header">
|
||||
<h4>已选人员</h4>
|
||||
<h6>共{{ tempUserToNames.length }}人</h6>
|
||||
<div class="close-btn" @click="isUserModalShow = false">
|
||||
<svg t="1626397122082" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3133" width="14" height="14">
|
||||
<path d="M877.216 491.808" p-id="3134" fill="#595959"></path>
|
||||
<path
|
||||
d="M575.328 510.496 946.784 140.672c17.568-17.504 17.664-45.824 0.192-63.424-17.504-17.632-45.792-17.664-63.36-0.192L512.032 446.944 143.712 77.216C126.304 59.712 97.92 59.648 80.384 77.12 62.848 94.624 62.816 123.008 80.288 140.576l368.224 369.632L77.216 879.808c-17.568 17.504-17.664 45.824-0.192 63.424 8.736 8.8 20.256 13.216 31.776 13.216 11.424 0 22.848-4.352 31.584-13.056l371.36-369.696 371.68 373.088C892.192 955.616 903.68 960 915.168 960c11.456 0 22.912-4.384 31.648-13.088 17.504-17.504 17.568-45.824 0.096-63.392L575.328 510.496 575.328 510.496zM575.328 510.496"
|
||||
p-id="3135"
|
||||
fill="#595959"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-popup_body">
|
||||
<ul class="user-popup_ul">
|
||||
<li v-for="item in tempUserToNames">
|
||||
<h4>{{ item.name }}</h4>
|
||||
<h6>{{ item.group }}</h6>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isUserModalShow" style="z-index: 103" class="my-modal" @click="isUserModalShow = false"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { Toast } from "vant";
|
||||
require("./index.scss");
|
||||
import tree from "./tree.vue";
|
||||
export default {
|
||||
components: { tree },
|
||||
props: {
|
||||
treeData: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
userids: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
model: {
|
||||
prop: "userids",
|
||||
event: "change",
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
checkTreeById: this.checkTreeById,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tempUserIds: [],
|
||||
firstTabIndex: 0,
|
||||
secondTabIndex: 0,
|
||||
tabData: [],
|
||||
currentTree: [],
|
||||
tabSliderStyle: {},
|
||||
searchHeadStyle: {},
|
||||
isPopupShow: false,
|
||||
isModalShow: false,
|
||||
isUserModalShow: false,
|
||||
isAllTreeCheck: false,
|
||||
isSearchShow: false,
|
||||
searchText: null,
|
||||
cacheMap: new Map(),
|
||||
duplicateIds: [],
|
||||
domId: "dom_" + new Date().getTime(),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
firstTabData() {
|
||||
if (this.treeData.length > 0) return this.treeData.map(x => x.name);
|
||||
else return [];
|
||||
},
|
||||
secondTabData() {
|
||||
if (this.treeData.length == 0) return [];
|
||||
return this.treeData[this.firstTabIndex].data.map(x => x.name);
|
||||
},
|
||||
currentTreeFlatten() {
|
||||
const flatten = (data, pid, pname) => {
|
||||
return data.reduce((arr, { id, name, children = [], type, isCheck }) => arr.concat([{ id, name, pid, type, isCheck, group: pname }], flatten(children, id, name)), []);
|
||||
};
|
||||
if (!this.currentTree) return [];
|
||||
var newArr = flatten(this.currentTree, 0, "");
|
||||
return newArr;
|
||||
},
|
||||
searchList() {
|
||||
const _this = this;
|
||||
let flattenArr = _this.currentTreeFlatten;
|
||||
flattenArr = flattenArr.filter(x => x.type == 2);
|
||||
if (!_this.searchText) return flattenArr;
|
||||
else return flattenArr.filter(x => x.name.indexOf(_this.searchText) > -1);
|
||||
},
|
||||
tempUserToNames() {
|
||||
const _this = this;
|
||||
let flattenArr = _this.currentTreeFlatten;
|
||||
var arr = flattenArr.filter(x => _this.tempUserIds.includes(x.id));
|
||||
return arr;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.tabData = this.treeData.map(x => x.name);
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
show() {
|
||||
let timer = null;
|
||||
if (this.firstTabData.length == 0) {
|
||||
Toast.loading({ forbidClick: true });
|
||||
timer = setTimeout(() => {
|
||||
this.show();
|
||||
}, 100);
|
||||
return;
|
||||
} else {
|
||||
Toast.clear();
|
||||
if (!!timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
|
||||
this.isModalShow = this.isPopupShow = true;
|
||||
this.tabBtnChange(0);
|
||||
var parentId = "#" + this.domId;
|
||||
setTimeout(() => {
|
||||
let treeH = document.querySelector(parentId + ".tree-popup").offsetHeight,
|
||||
headerH = document.querySelector(parentId + " .tree-popup_header").offsetHeight;
|
||||
document.querySelector(parentId + " .tree-popup_body").style.height = treeH - headerH - 60 + "px";
|
||||
this.searchHeadStyle = { top: headerH + "px" };
|
||||
}, 0);
|
||||
},
|
||||
popupColse() {
|
||||
this.isPopupShow = false;
|
||||
this.firstTabIndex = 0;
|
||||
this.secondTabIndex = 0;
|
||||
setTimeout(() => {
|
||||
this.isModalShow = false;
|
||||
}, 250);
|
||||
},
|
||||
tabBtnChange(index) {
|
||||
this.firstTabIndex = index;
|
||||
this.getTabSliderStyle(index);
|
||||
this.changeEmpty();
|
||||
this.tabCardChange(0);
|
||||
},
|
||||
tabCardChange(index) {
|
||||
const _this = this;
|
||||
var wrap = document.querySelector("#" + this.domId + " .item-wrap");
|
||||
var tabs = document.querySelectorAll("#" + this.domId + " .item-tab_card");
|
||||
let currentItem = tabs[index];
|
||||
var pageX = document.documentElement.clientWidth,
|
||||
blockW = currentItem.scrollWidth,
|
||||
moveX = 0;
|
||||
for (let i = 0; i < tabs.length; i++) {
|
||||
const element = tabs[i];
|
||||
if (i > index) break;
|
||||
moveX += element.scrollWidth;
|
||||
}
|
||||
var left = moveX - pageX / 2 + blockW / 2;
|
||||
wrap.scrollLeft = left;
|
||||
|
||||
this.secondTabIndex = index;
|
||||
this.isAllTreeCheck = false;
|
||||
this.isSearchShow = false;
|
||||
this.initTreeData();
|
||||
},
|
||||
initTreeData() {
|
||||
const _this = this;
|
||||
const checkTree = tree => {
|
||||
_this.currentTree = tree;
|
||||
_this.tempUserIds = JSON.parse(JSON.stringify(_this.userids));
|
||||
let duplArr = _this.duplicateIds.map(x => x.id);
|
||||
_this.tempUserIds.forEach(element => {
|
||||
let id = element;
|
||||
if (duplArr.length > 0 && duplArr.includes(element)) {
|
||||
let parent = _this.duplicateIds.find(x => x.id == element);
|
||||
//处理重复id逻辑,仅选择第一个
|
||||
parent && (id += "," + parent.pid[0]);
|
||||
}
|
||||
_this.checkTreeById(id, true);
|
||||
});
|
||||
};
|
||||
let first = _this.firstTabIndex,
|
||||
second = _this.secondTabIndex,
|
||||
cacheMap = _this.cacheMap,
|
||||
tData = _this.treeData;
|
||||
var tree = tData[first].data[second].data;
|
||||
var cacheKey = first + "," + second;
|
||||
if (!!tree && typeof tree === "function") {
|
||||
var cacheData = cacheMap.get(cacheKey);
|
||||
if (!cacheData) {
|
||||
tree().then(data => {
|
||||
_this.duplicateIds = _this.dupTreeIds(data);
|
||||
var jtree = JSON.parse(JSON.stringify(data));
|
||||
cacheMap.set(cacheKey, jtree);
|
||||
var ftree = _this.formatTree(jtree);
|
||||
checkTree(ftree);
|
||||
});
|
||||
} else {
|
||||
var ftree = _this.formatTree(cacheData);
|
||||
checkTree(ftree);
|
||||
}
|
||||
} else {
|
||||
_this.duplicateIds = _this.dupTreeIds(tree);
|
||||
var jtree = JSON.parse(JSON.stringify(tree));
|
||||
var ftree = _this.formatTree(jtree);
|
||||
checkTree(ftree);
|
||||
}
|
||||
},
|
||||
getTabSliderStyle(index) {
|
||||
var dom = document.querySelectorAll(".item-tab_btn")[index];
|
||||
if (!dom) return;
|
||||
this.tabSliderStyle = {
|
||||
width: dom.offsetWidth + "px",
|
||||
transform: `translateX(${dom.offsetLeft}px)`,
|
||||
};
|
||||
},
|
||||
saveAllCheck() {
|
||||
const _this = this;
|
||||
_this.isAllTreeCheck = !_this.isAllTreeCheck;
|
||||
const recursionCheckAll = (tree, checked) => {
|
||||
tree.forEach(element => {
|
||||
element.isCheck = checked;
|
||||
if (typeof element.children !== "undefined" && element.children.length > 0) recursionCheckAll(element.children, checked);
|
||||
});
|
||||
};
|
||||
recursionCheckAll(_this.currentTree, _this.isAllTreeCheck);
|
||||
_this.getTreeCheckIds();
|
||||
},
|
||||
changeEmpty() {
|
||||
this.tempUserIds = [];
|
||||
},
|
||||
submit() {
|
||||
const _this = this;
|
||||
let objArr = [],
|
||||
idsArr = this.tempUserIds.map(x => _this.getSplitId(x));
|
||||
idsArr = Array.from(new Set(idsArr));
|
||||
this.$emit("change", idsArr);
|
||||
function delKey(obj, ...args) {
|
||||
args.forEach(v => delete obj[v]);
|
||||
return obj;
|
||||
}
|
||||
idsArr.forEach(element => {
|
||||
let findObj = _this.currentTreeFlatten.find(x => _this.getSplitId(x.id) == element);
|
||||
delKey(findObj, "id", "isCheck", "pid", "type");
|
||||
objArr.push({ ...findObj, id: element });
|
||||
});
|
||||
this.$emit("on-submit", objArr);
|
||||
this.popupColse();
|
||||
},
|
||||
getSplitId(strId) {
|
||||
if (typeof strId === "string" && strId.indexOf(",") != -1) return parseInt(strId.split(",")[0]);
|
||||
else return strId;
|
||||
},
|
||||
//#region treeOpera
|
||||
formatTree(tree, level = 0) {
|
||||
const _this = this;
|
||||
tree.forEach(element => {
|
||||
var findObj = _this.duplicateIds.map(x => x.id).find(x => x == element.id);
|
||||
if (!!findObj) element.id = element.id + "," + element.pid; //重复id加上组id以免重复
|
||||
element.show = level == 0;
|
||||
element.isCheck = false;
|
||||
element.type = 1;
|
||||
if (typeof element.children !== "undefined" && element.children.length > 0) element.children = _this.formatTree(element.children, level + 1);
|
||||
else {
|
||||
// element.id = element.id + "," + element.pid; //防止用户在多个组重复id,加上组id以免重复
|
||||
element.type = 2;
|
||||
}
|
||||
});
|
||||
return tree;
|
||||
},
|
||||
flattenTree(tree) {
|
||||
const flatten = (data, pid) => {
|
||||
return data.reduce((arr, { id, name, children = [], type }) => arr.concat([{ id, name, type, pid }], flatten(children, id)), []);
|
||||
};
|
||||
return flatten(tree, 0);
|
||||
},
|
||||
dupTreeIds(tree) {
|
||||
//一个人可能在多个组,取出这些id
|
||||
const flatten = (data, pid) => {
|
||||
return data.reduce((arr, { id, name, children = [] }) => arr.concat([{ id, name, pid }], flatten(children, id)), []);
|
||||
};
|
||||
// var flattenArr = flatten(tree, 0);
|
||||
|
||||
var flattenArr = this.flattenTree(tree);
|
||||
var ctnArr = flattenArr.reduce((arr, { id, pid }) => {
|
||||
var findObj = arr.find(x => x.id == id);
|
||||
if (!!findObj) {
|
||||
findObj.count += 1;
|
||||
findObj.pid.push(pid);
|
||||
} else arr.push({ id, count: 1, pid: [pid] });
|
||||
return arr;
|
||||
}, []);
|
||||
// var dupArr = ctnArr.filter((x) => x.count > 1).map((x) => x.id);
|
||||
var dupArr = ctnArr.filter(x => x.count > 1);
|
||||
return dupArr;
|
||||
},
|
||||
findTreePids(id, tree) {
|
||||
const _this = this;
|
||||
var flattenArr = _this.flattenTree(tree);
|
||||
var arr = [];
|
||||
while (id > 0) {
|
||||
var findObj = flattenArr.find(x => x.id == id);
|
||||
if (findObj) {
|
||||
id = findObj.pid;
|
||||
arr.push(id);
|
||||
} else {
|
||||
id = -1;
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
},
|
||||
findTreeChildIds(id, tree) {
|
||||
const _this = this;
|
||||
const recursionChildIds = tree => {
|
||||
let arrIds = [];
|
||||
for (const key in tree) {
|
||||
const element = tree[key];
|
||||
arrIds.push(element.id);
|
||||
if (typeof element.children !== "undefined" && element.children) {
|
||||
var childIds = recursionChildIds(element.children);
|
||||
arrIds = [...arrIds, ...childIds];
|
||||
}
|
||||
}
|
||||
return arrIds;
|
||||
};
|
||||
let childTree = [];
|
||||
if (id == 0) childTree = tree;
|
||||
else {
|
||||
var ctree = _this.findTreeByid(id, tree);
|
||||
if (ctree && typeof ctree.children !== "undefined" && ctree.children) childTree = ctree.children;
|
||||
else return [];
|
||||
}
|
||||
|
||||
var ids = recursionChildIds(childTree);
|
||||
return ids;
|
||||
},
|
||||
findTreeByid(id, tree) {
|
||||
const _this = this;
|
||||
var findTree;
|
||||
for (const key in tree) {
|
||||
const element = tree[key];
|
||||
if (element.id == id) findTree = element;
|
||||
if (typeof element.children !== "undefined" && element.children && !findTree) {
|
||||
findTree = _this.findTreeByid(id, element.children);
|
||||
}
|
||||
}
|
||||
return findTree;
|
||||
},
|
||||
findTreeByPid(id, tree) {
|
||||
const _this = this;
|
||||
var findId;
|
||||
for (const key in tree) {
|
||||
const element = tree[key];
|
||||
if (element.id == id) {
|
||||
findId = element.pid;
|
||||
}
|
||||
if (typeof element.children !== "undefined" && element.children && !findId) {
|
||||
findId = _this.findTreeByPid(id, element.children);
|
||||
}
|
||||
}
|
||||
return findId;
|
||||
},
|
||||
checkTreeById(id, checked) {
|
||||
const _this = this;
|
||||
var pids = this.findTreePids(id, this.currentTree);
|
||||
var cids = this.findTreeChildIds(id, this.currentTree);
|
||||
var idArr = [...cids, id];
|
||||
checked && (idArr = [...pids, ...idArr]);
|
||||
idArr.forEach(element => {
|
||||
var t = this.findTreeByid(element, this.currentTree);
|
||||
t && (t.isCheck = checked);
|
||||
});
|
||||
|
||||
if (!checked) {
|
||||
pids.forEach(element => {
|
||||
var t = _this.findTreeByid(element, this.currentTree);
|
||||
if (!t || typeof t.children === "undefined") return;
|
||||
var findIndex = t.children.findIndex(x => x.isCheck && x.id != id);
|
||||
findIndex === -1 && (t.isCheck = false);
|
||||
});
|
||||
}
|
||||
this.getTreeCheckIds();
|
||||
},
|
||||
getTreeCheckIds() {
|
||||
const _this = this;
|
||||
var isEndWithType = true; //是否只返回最末端的结点(type=2)
|
||||
const recursionCheckIds = tree => {
|
||||
let arrIds = [];
|
||||
for (const key in tree) {
|
||||
const element = tree[key];
|
||||
if (element.isCheck && (isEndWithType ? element.type == 2 : true)) arrIds.push(element.id);
|
||||
if (typeof element.children !== "undefined" && element.children) {
|
||||
var childIds = recursionCheckIds(element.children);
|
||||
arrIds = [...arrIds, ...childIds];
|
||||
}
|
||||
}
|
||||
return arrIds;
|
||||
};
|
||||
var t = recursionCheckIds(_this.currentTree);
|
||||
this.tempUserIds = t;
|
||||
},
|
||||
//#endregion
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<ul class="conta-wrap">
|
||||
<li v-for="(item, index) in treeData">
|
||||
<div
|
||||
:class="['tree-item', getItemClass(item)]"
|
||||
:style="{ 'padding-left': 30 * level + 12 + 'px' }"
|
||||
@click="itemClick(item)"
|
||||
>
|
||||
<a
|
||||
href="javascript:;"
|
||||
style="dispaly: block"
|
||||
@click.stop="itemCheck(item, $event)"
|
||||
>
|
||||
<input type="checkbox" v-model="item.isCheck" />
|
||||
<span
|
||||
:class="[
|
||||
'my-checkbox-core',
|
||||
item.isCheck ? 'active' : '',
|
||||
]"
|
||||
></span>
|
||||
<label>{{ item.name }}</label>
|
||||
</a>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<tree
|
||||
v-if="item.show"
|
||||
:userids="userids"
|
||||
:treeData="item.children"
|
||||
:level="level + 1"
|
||||
></tree>
|
||||
</transition>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
require("./index.scss");
|
||||
export default {
|
||||
name: "tree",
|
||||
inject: ["checkTreeById"],
|
||||
props: {
|
||||
level: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
treeData: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
userids: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getItemClass(item) {
|
||||
if (item.type == 2) return;
|
||||
let className = " tree-item_" + (item.show ? "open" : "close");
|
||||
className += this.level === 0 ? " tree-item_group " : "";
|
||||
return className;
|
||||
},
|
||||
itemCheck(item, e) {
|
||||
if (
|
||||
typeof e !== "undefined" &&
|
||||
e.target.tagName.toLowerCase() === "input"
|
||||
)
|
||||
return;
|
||||
this.checkTreeById(item.id, !item.isCheck);
|
||||
},
|
||||
itemClick(item) {
|
||||
if (item.type == 2) {
|
||||
// this.itemCheck(item);
|
||||
this.checkTreeById(item.id, !item.isCheck);
|
||||
} else if (item.type == 1) {
|
||||
item.show = !item.show;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<Modal v-model="modal" :title="name" @on-visible-change="showChange" width="70%" footer-hide>
|
||||
<Button class="js_copy_code" data-clipboard-action="copy" :data-clipboard-text="currentHtml">复制代码</Button>
|
||||
<div v-highlight>
|
||||
<pre v-show="isLoad">
|
||||
<code id="test" class="html"></code>
|
||||
</pre>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { load } from "../../assets/js/code";
|
||||
export default {
|
||||
props: {
|
||||
name: String,
|
||||
url: String,
|
||||
type: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
modal: false,
|
||||
isLoad: false,
|
||||
currentHtml: null,
|
||||
clipboard: null,
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
const _this = this;
|
||||
this.modal = true;
|
||||
this.isLoad = false;
|
||||
let { html, encode } = await load(_this.url);
|
||||
$("#test").attr("class", _this.type).html(encode);
|
||||
this.isLoad = true;
|
||||
this.currentHtml = html;
|
||||
this.clipboard = new ClipboardJS(".js_copy_code");
|
||||
this.clipboard.on("success", function (e) {
|
||||
_this.$Message.success("copy success!");
|
||||
e.clearSelection();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
showChange(state) {
|
||||
if (!state) this.destroy();
|
||||
},
|
||||
destroy() {
|
||||
this.clipboard.destroy();
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(this.$el);
|
||||
}, 300);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,24 @@
|
||||
import Vue from "vue";
|
||||
import codemodal from "./code_modal.vue";
|
||||
import { Message } from "view-design";
|
||||
export default props => {
|
||||
// 创建实例
|
||||
const vm = new Vue({
|
||||
render(h) {
|
||||
// h为createElement,返回VNode虚拟Node
|
||||
return h(codemodal, { props });
|
||||
}
|
||||
}).$mount();
|
||||
|
||||
// 手动挂载实例到body
|
||||
document.body.appendChild(vm.$el);
|
||||
|
||||
const comp = vm.$children[0];
|
||||
// 销毁方法
|
||||
// comp.remove = function() {
|
||||
// document.body.removeChild(vm.$el);
|
||||
// vm.$destroy();
|
||||
// };
|
||||
// 返回组件
|
||||
return comp;
|
||||
};
|
||||
@@ -0,0 +1,240 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 富文本编辑器 -->
|
||||
<quill-editor v-model="content"
|
||||
ref="myTextEditor"
|
||||
:options="editorOption"
|
||||
@change="onChange"
|
||||
>
|
||||
<div id="toolbar" slot="toolbar">
|
||||
<span class="ql-formats"><button type="button" class="ql-bold"></button></span>
|
||||
<span class="ql-formats"><button type="button" class="ql-italic"></button></span>
|
||||
<span class="ql-formats"><button type="button" class="ql-underline"></button></span>
|
||||
<span class="ql-formats"><button type="button" class="ql-strike"></button></span>
|
||||
<!-- 有序和无序 -->
|
||||
<span class="ql-formats"><button type="button" class="ql-list" value="ordered"></button></span>
|
||||
<span class="ql-formats"><button type="button" class="ql-list" value="bullet"></button></span>
|
||||
<!-- 缩进 -->
|
||||
<span class="ql-formats"><button type="button" class="ql-indent" value="-1"></button></span>
|
||||
<span class="ql-formats"><button type="button" class="ql-indent" value="+1"></button></span>
|
||||
<span class="ql-formats"> <button type="button" class="ql-direction" value="rtl"></button></span>
|
||||
<!-- 自定义下拉 -->
|
||||
<span class="ql-formats">
|
||||
<select class="ql-size" id="ql-size">
|
||||
<option value="small">小号</option>
|
||||
<option value="">正常</option>
|
||||
<option value="large">大号</option>
|
||||
<option value="huge">特大</option>
|
||||
</select>
|
||||
<!-- <i-select size="small" @on-change="mychange">
|
||||
<i-option value="small">小号</i-option>
|
||||
<i-option value="large">正常</i-option>
|
||||
<i-option value="huge">特大</i-option>
|
||||
</i-select> -->
|
||||
</span>
|
||||
<span class="ql-formats">
|
||||
<select class="ql-header">
|
||||
<option value="1">标题1</option>
|
||||
<option value="2">标题2</option>
|
||||
<option value="3">标题3</option>
|
||||
<option value="4">标题4</option>
|
||||
<option value="5">标题5</option>
|
||||
<option value="6">标题6</option>
|
||||
<option selected="selected">正文</option>
|
||||
</select>
|
||||
</span>
|
||||
<span class="ql-formats">
|
||||
<select class="ql-color" v-model="fontColor">
|
||||
<option v-for="item in colorArry" :key="item" :value="'#'+item"></option>
|
||||
</select>
|
||||
</span>
|
||||
<span class="ql-formats">
|
||||
<select class="ql-background" v-model="bgColor">
|
||||
<option v-for="item in colorArry" :key="item" :value="'#'+item"></option>
|
||||
</select>
|
||||
</span>
|
||||
<span class="ql-formats">
|
||||
<select class="ql-font">
|
||||
<option selected="selected"></option>
|
||||
<option value="serif"></option>
|
||||
<option value="monospace"></option>
|
||||
</select>
|
||||
</span>
|
||||
<span class="ql-formats">
|
||||
<select class="ql-align">
|
||||
<option selected="selected"></option>
|
||||
<option value="center"></option>
|
||||
<option value="right"></option>
|
||||
<option value="justify"></option>
|
||||
</select>
|
||||
</span>
|
||||
<!-- <span class="ql-formats">
|
||||
<button type="button" @click="isLink=true" class="ql-link"></button>
|
||||
</span> -->
|
||||
<span class="ql-formats">
|
||||
<button type="button" class="my-formats-image">
|
||||
<Upload
|
||||
:action="formItem.uploadUrl"
|
||||
:on-success="handleSuccess"
|
||||
:data="uploadData"
|
||||
accept="image/gif,image/jpeg,image/jpg,image/png">
|
||||
<Icon type="image" size="16"></Icon>
|
||||
</Upload>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</quill-editor>
|
||||
<!-- 添加链接 -->
|
||||
<Modal v-model="isLink" title="添加链接" width="450px">
|
||||
<i-form :label-width="85" class="myform" ref="formItem.link" :model="formItem.link">
|
||||
<Form-Item label="链接地址:" prop="url">
|
||||
<i-input v-model="formItem.link.url" placeholder="请输入链接地址"></i-input>
|
||||
</Form-Item>
|
||||
<Form-Item label="链接名称:" prop="tit">
|
||||
<i-input v-model="formItem.link.tit" placeholder="请输入链接名称"></i-input>
|
||||
</Form-Item>
|
||||
</i-form>
|
||||
<div slot="footer">
|
||||
<i-Button type="primary" @click="addLinkSave()">提交</i-Button>
|
||||
<i-Button type="ghost" @click="myCancel('isLink','formItem.link')" style="margin-left: 8px">取消</i-Button>
|
||||
</div>
|
||||
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
// import {quillEditor} from 'vue-quill-editor'
|
||||
|
||||
export default {
|
||||
// components: {quillEditor},
|
||||
props: {
|
||||
// 提示内容
|
||||
placeholder:{
|
||||
type: String
|
||||
},
|
||||
/*编辑器内容*/
|
||||
value: {
|
||||
type: String
|
||||
},
|
||||
/*上传图片的地址*/
|
||||
uploadUrl: {
|
||||
type: String
|
||||
},
|
||||
readonly:Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
content:this.value,
|
||||
size:'',
|
||||
fontColor:"000000",
|
||||
bgColor:"ffffff",
|
||||
colorArry:['000000','e60000','ff9900','ffff00','008a00','0066cc','9933ff','ffffff','facccc','ffebcc','ffffcc','cce8cc','cce0f5','ebd6ff','bbbbbb','f06666','ffc266','ffff66','66b966','66a3e0','c285ff','888888','a10000','b26b00','b2b200','006100','0047b2','6b24b2','444444','5c0000','663d00','666600','003700','002966','3d1466'],
|
||||
editorOption: {
|
||||
modules: {
|
||||
toolbar: '#toolbar',
|
||||
},
|
||||
placeholder:this.placeholder || '请输入内容……',
|
||||
readOnly: this.readonly,
|
||||
},
|
||||
showCrop:false,
|
||||
isLink:false,
|
||||
isImage:false,
|
||||
formItem:{
|
||||
link:{
|
||||
url:'',
|
||||
tit:'',
|
||||
},
|
||||
uploadUrl:this.uploadUrl || '',
|
||||
},
|
||||
uploadData:{
|
||||
AppType:window.location.pathname.split('/')[1],
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onChange(){
|
||||
this.$emit('input', this.content)
|
||||
},
|
||||
myCancel(name, resetName) {
|
||||
var vm = this;
|
||||
vm[name] = false;
|
||||
if (resetName) {
|
||||
console.log(vm.$refs[resetName])
|
||||
this.$refs[resetName].resetFields();
|
||||
}
|
||||
},
|
||||
addLinkSave(){
|
||||
var _that=this;
|
||||
_that.isLink=false;
|
||||
_that.editor.focus();
|
||||
_that.editor.insertText(_that.editor.getSelection().index, ' ', '', true);
|
||||
_that.editor.insertText(_that.editor.getSelection().index-1, _that.formItem.link.tit+' ', 'link','http://'+ _that.formItem.link.url);
|
||||
},
|
||||
handleSuccess(res, file){
|
||||
this.editor.focus();
|
||||
console.log(res);
|
||||
var url=res.host+res.fileurl;
|
||||
this.editor.insertEmbed(this.editor.getSelection().index, 'image', url);
|
||||
},
|
||||
// onFocus(){
|
||||
// $(".ql-editor img").removeClass("active");
|
||||
// },
|
||||
},
|
||||
computed: {
|
||||
editor() {
|
||||
return this.$refs.myTextEditor.quill;
|
||||
}
|
||||
},
|
||||
|
||||
mounted(){
|
||||
var _that=this;
|
||||
// $(".ql-editor img").on('click',function(){
|
||||
// _that.editor.blur();
|
||||
// $(this).addClass("active");
|
||||
// })
|
||||
},
|
||||
watch: {
|
||||
'value'(newVal, oldVal) {
|
||||
if (this.editor) {
|
||||
if (newVal !== this.content) {
|
||||
this.content = newVal
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.ql-tooltip{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.my-formats-image{
|
||||
outline: none;
|
||||
ul.ivu-upload-list{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.ql-container .ql-editor {
|
||||
min-height: 20em;
|
||||
padding-bottom: 1em;
|
||||
max-height: 25em;
|
||||
}
|
||||
.ql-editor{
|
||||
position: relative;
|
||||
img{
|
||||
position: relative;
|
||||
}
|
||||
img::after {
|
||||
content:'123123';
|
||||
display: block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
position: absolute;
|
||||
top:0;right: 0;
|
||||
background: red;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<Modal v-model="modal" @on-visible-change="showChange" :title="title || '提示'">
|
||||
<Alert type="warning" class="mb-1" show-icon>
|
||||
<Icon type="ios-bulb-outline" :class="{ 'mt-5': !info }" slot="icon" :size="28"></Icon>
|
||||
<div v-if="msg" :class="['message-box', info ? '' : 'mt-10 mb-10 ml-10']">{{ msg }}</div>
|
||||
<span v-if="info" slot="desc">{{ info }}</span>
|
||||
</Alert>
|
||||
<div slot="footer">
|
||||
<Button type="primary" @click="ok">确定</Button>
|
||||
<Button @click="cancle">取消</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
title: String,
|
||||
msg: String,
|
||||
info: String,
|
||||
onOk: Function,
|
||||
onCancel: Function,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
modal: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.modal = true;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
ok() {
|
||||
this.modal = false;
|
||||
typeof this.onOk === "function" && this.onOk();
|
||||
},
|
||||
cancle() {
|
||||
this.modal = false;
|
||||
typeof this.onCancel === "function" && this.onCancel();
|
||||
},
|
||||
showChange(state) {
|
||||
if (!state) this.destroy();
|
||||
},
|
||||
destroy() {
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(this.$el);
|
||||
}, 300);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.my-confirwm {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.message-box {
|
||||
font-size: 16px;
|
||||
color: #17233d;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,23 @@
|
||||
import Vue from "vue";
|
||||
import confirm from "./confirm.vue";
|
||||
export default props => {
|
||||
// 创建实例
|
||||
const vm = new Vue({
|
||||
render(h) {
|
||||
// h为createElement,返回VNode虚拟Node
|
||||
return h(confirm, { props });
|
||||
}
|
||||
}).$mount();
|
||||
|
||||
// 手动挂载实例到body
|
||||
document.body.appendChild(vm.$el);
|
||||
|
||||
const comp = vm.$children[0];
|
||||
// 销毁方法
|
||||
// comp.remove = function() {
|
||||
// document.body.removeChild(vm.$el);
|
||||
// vm.$destroy();
|
||||
// };
|
||||
// 返回组件
|
||||
return comp;
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<div :id="domId" :ref="domId" class="ztree"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
require("@public/libs/ztree/zTreeStyle.css");
|
||||
import "@public/libs/ztree/jquery.ztree.all.min.js";
|
||||
export default {
|
||||
props: {
|
||||
treeData: {
|
||||
type: Object,
|
||||
},
|
||||
setting: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
domId: "",
|
||||
treeSetting: {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showIcon: false,
|
||||
},
|
||||
check: {
|
||||
enable: false,
|
||||
},
|
||||
callback: {},
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.$watch("treeData", (val) => {
|
||||
if (val) {
|
||||
this.$nextTick(() => {
|
||||
this.initTree(this.treeData, this.domId);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
this.domId = this.uuid();
|
||||
},
|
||||
methods: {
|
||||
uuid() {
|
||||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
|
||||
/[xy]/g,
|
||||
function (c) {
|
||||
var r = (Math.random() * 16) | 0,
|
||||
v = c == "x" ? r : (r & 0x3) | 0x8;
|
||||
return v.toString(16);
|
||||
}
|
||||
);
|
||||
},
|
||||
initTree(_data, _domId) {
|
||||
const _this = this;
|
||||
_this.treeSetting.callback.onClick = (
|
||||
event,
|
||||
treeId,
|
||||
treeNode,
|
||||
clickFlag
|
||||
) => {
|
||||
// console.log(event, treeId, treeNode, clickFlag);
|
||||
_this.$emit("on-tree-click", treeNode);
|
||||
};
|
||||
var zNodes = _this.openFistNode(_data);
|
||||
$.fn.zTree.init($("#" + _domId), _this.treeSetting, zNodes);
|
||||
var treeObj = $.fn.zTree.getZTreeObj(_domId);
|
||||
var nodes = treeObj.getNodes();
|
||||
if (nodes && nodes.length > 0) {
|
||||
setTimeout(function () {
|
||||
$("#" + nodes[0].tId + "_a").click();
|
||||
}, 0);
|
||||
}
|
||||
},
|
||||
openFistNode(_zNodes) {
|
||||
//展开一级节点
|
||||
if (_zNodes && _zNodes.length > 0) {
|
||||
for (var key in _zNodes) {
|
||||
if (_zNodes.hasOwnProperty(key)) {
|
||||
var element = _zNodes[key];
|
||||
element.open = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_zNodes.open = true;
|
||||
}
|
||||
return _zNodes;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<div :id="domId" :ref="domId" class="ztree"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
require("@public/libs/ztree/zTreeStyle.css");
|
||||
import "@public/libs/ztree/jquery.ztree.all.min.js";
|
||||
export default {
|
||||
props: {
|
||||
treeData: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
setting: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
// 外部传入需要默认选中的节点id,不传则选中第一个一级节点
|
||||
selectId: {
|
||||
type: [Number, String],
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
domId: "",
|
||||
treeSetting: {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showIcon: false,
|
||||
},
|
||||
check: {
|
||||
enable: false,
|
||||
},
|
||||
callback: {},
|
||||
},
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
treeData(val) {
|
||||
if (val && val.length) {
|
||||
this.$nextTick(() => {
|
||||
this.initTree(this.treeData, this.domId);
|
||||
});
|
||||
}
|
||||
},
|
||||
// 监听外部传入选中id变化,自动重新选中
|
||||
selectId() {
|
||||
this.$nextTick(() => {
|
||||
this.handleDefaultSelect();
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$watch("treeData", (val) => {
|
||||
if (val) {
|
||||
this.$nextTick(() => {
|
||||
this.initTree(this.treeData, this.domId);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
this.domId = this.uuid();
|
||||
},
|
||||
methods: {
|
||||
getZtreeInstance() {
|
||||
return $.fn.zTree.getZTreeObj(this.domId);
|
||||
},
|
||||
uuid() {
|
||||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
|
||||
/[xy]/g,
|
||||
function (c) {
|
||||
var r = (Math.random() * 16) | 0,
|
||||
v = c == "x" ? r : (r & 0x3) | 0x8;
|
||||
return v.toString(16);
|
||||
}
|
||||
);
|
||||
},
|
||||
/**
|
||||
* 核心方法:根据节点id选中节点,并逐层展开所有父节点
|
||||
* @param {String|Number} targetId 目标节点id
|
||||
*/
|
||||
selectNodeById(targetId) {
|
||||
const treeObj = $.fn.zTree.getZTreeObj(this.domId);
|
||||
if (!treeObj || !targetId) return;
|
||||
|
||||
const targetNode = treeObj.getNodeByParam('id', targetId);
|
||||
if (!targetNode) return;
|
||||
|
||||
// 高亮选中节点
|
||||
treeObj.selectNode(targetNode);
|
||||
|
||||
// 循环向上展开所有父节点
|
||||
let currNode = targetNode;
|
||||
while (currNode) {
|
||||
treeObj.expandNode(currNode, true, false, false);
|
||||
currNode = currNode.getParentNode();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 默认选中逻辑:有selectId选对应节点,无则选第一个一级节点
|
||||
*/
|
||||
handleDefaultSelect() {
|
||||
const treeObj = $.fn.zTree.getZTreeObj(this.domId);
|
||||
if (!treeObj) return;
|
||||
|
||||
const rootNodes = treeObj.getNodes();
|
||||
if (!rootNodes || rootNodes.length === 0) return;
|
||||
|
||||
if (this.selectId !== null && this.selectId !== undefined) {
|
||||
// 外部传入id,选中指定节点
|
||||
this.selectNodeById(this.selectId);
|
||||
} else {
|
||||
// 无传入id,默认选中第一个一级节点
|
||||
const firstRoot = rootNodes[0];
|
||||
treeObj.selectNode(firstRoot);
|
||||
treeObj.expandNode(firstRoot, true, false, false);
|
||||
}
|
||||
},
|
||||
initTree(_data, _domId) {
|
||||
const _this = this;
|
||||
// 合并自定义setting
|
||||
_this.treeSetting = Object.assign({}, _this.treeSetting, _this.setting);
|
||||
|
||||
// 绑定点击回调
|
||||
_this.treeSetting.callback.onClick = (event, treeId, treeNode) => {
|
||||
_this.$emit("on-tree-click", treeNode);
|
||||
};
|
||||
// 绑定复选框点击回调
|
||||
_this.treeSetting.callback.onCheck = (event, treeId, treeNode) => {
|
||||
const zTreeObj = $.fn.zTree.getZTreeObj(treeId);
|
||||
// getCheckedNodes(true) 获取所有手动勾选节点,不分层级
|
||||
const allChecked = zTreeObj.getCheckedNodes(true);
|
||||
this.$emit('on-tree-Check', allChecked);
|
||||
};
|
||||
// 展开所有一级节点
|
||||
var zNodes = _this.openFistNode(_data);
|
||||
// 初始化树
|
||||
$.fn.zTree.init($("#" + _domId), _this.treeSetting, zNodes);
|
||||
// 执行默认选中逻辑
|
||||
this.$nextTick(() => {
|
||||
this.handleDefaultSelect();
|
||||
})
|
||||
},
|
||||
openFistNode(_zNodes) {
|
||||
if (_zNodes && _zNodes.length > 0) {
|
||||
for (var i = 0; i < _zNodes.length; i++) {
|
||||
_zNodes[i].open = true;
|
||||
}
|
||||
}
|
||||
return _zNodes;
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div>
|
||||
<Table
|
||||
:columns="columns"
|
||||
:data="listData"
|
||||
@on-selection-change="selectChange"
|
||||
class="link-table table-bottom-box"
|
||||
:height="tableHeight"
|
||||
no-data-text="暂无数据"
|
||||
></Table>
|
||||
<div class="page-panel">
|
||||
<div class="fl">
|
||||
<slot :sel-ids="selectList"></slot>
|
||||
</div>
|
||||
<Page
|
||||
class="fr"
|
||||
:total="total"
|
||||
:current="dataParmas.page"
|
||||
:page-size="dataParmas.count"
|
||||
:page-size-opts="[10, 20, 30, 40]"
|
||||
@on-page-size-change="pageSizeUpdate"
|
||||
@on-change="pageUpdate"
|
||||
placement="top"
|
||||
show-total
|
||||
show-sizer
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
tableHeight: {
|
||||
default: 0,
|
||||
type: Number,
|
||||
},
|
||||
dataUrl: {
|
||||
default: "",
|
||||
type: String,
|
||||
},
|
||||
dataParmas: {
|
||||
default: {},
|
||||
type: Object,
|
||||
},
|
||||
dataFilter: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
columns: {
|
||||
default: [],
|
||||
type: Array,
|
||||
},
|
||||
autoLoad: {
|
||||
default: true,
|
||||
Type: Boolean,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
listData: [],
|
||||
selectList: [],
|
||||
total: 30,
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.dataParmas.page = 1;
|
||||
this.dataParmas.count = parseInt(localStorage.getItem("customPageCount") || 10);
|
||||
if (this.autoLoad) this.getData();
|
||||
},
|
||||
|
||||
methods: {
|
||||
getData() {
|
||||
const _this = this;
|
||||
let item = {},
|
||||
{ dataUrl, dataParmas } = this;
|
||||
// console.log("dataParmas", dataParmas);
|
||||
for (const key in dataParmas) {
|
||||
const element = dataParmas[key];
|
||||
item[key] = element;
|
||||
}
|
||||
_this.$api.get(dataUrl, item, resp => {
|
||||
let rData = resp.data;
|
||||
if (typeof _this.dataFilter === "function") {
|
||||
let fData = _this.dataFilter(rData);
|
||||
_this.listData = JSON.parse(JSON.stringify(fData));
|
||||
} else _this.listData = rData;
|
||||
});
|
||||
},
|
||||
selectChange(selection) {
|
||||
this.selectList = selection;
|
||||
},
|
||||
pageUpdate(page) {
|
||||
this.dataParmas.page = page;
|
||||
this.getData();
|
||||
},
|
||||
pageSizeUpdate(size) {
|
||||
this.dataParmas.page = 1;
|
||||
this.dataParmas.count = size;
|
||||
localStorage.setItem("customPageCount", size);
|
||||
this.getData();
|
||||
},
|
||||
reloadData() {
|
||||
this.getData();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<div class="type_set-box">
|
||||
<div class="type_name">
|
||||
<i class="iconfont icon-stop fl mr-10" v-if="!isEdit && !active" style="color: #ff5959"></i>
|
||||
<Input v-if="isEdit" v-model="type.name" ref="type_input" @on-blur="update" @on-enter="update" />
|
||||
<span v-else class="fl">{{ type.name }}</span>
|
||||
</div>
|
||||
<div class="type_action flex">
|
||||
<div class="action_item" @click="open">
|
||||
<span v-if="active">停用</span>
|
||||
<span v-else>启用</span>
|
||||
</div>
|
||||
<div class="action_edit" @click="edit">
|
||||
<span>编辑</span>
|
||||
</div>
|
||||
<div class="action_delete" @click="remove">
|
||||
<span>删除</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="divider2"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "TypeSetBox",
|
||||
props: {
|
||||
type: {
|
||||
name: { type: String, default: "" },
|
||||
id: { type: String, default: "" },
|
||||
},
|
||||
active: { type: Boolean, default: true },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isEdit: false,
|
||||
eventType: "",
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
type: {
|
||||
deep: true,
|
||||
handler(newVal) {
|
||||
if (this.isEdit) {
|
||||
this.isEdit = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
"type.name"(newVal) {
|
||||
if (this.isEdit) {
|
||||
this.isEdit = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.$emit("active", this.type.id);
|
||||
},
|
||||
edit() {
|
||||
this.isEdit = !this.isEdit;
|
||||
if (this.isEdit) this.$nextTick(() => this.$refs["type_input"].focus());
|
||||
},
|
||||
update(e) {
|
||||
if (!this.type.name) {
|
||||
this.$Message.error("值不得为空!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.eventType == "") {
|
||||
this.eventType = e.type;
|
||||
this.isEdit = false;
|
||||
this.$emit("edit", this.type.id, this.type.name);
|
||||
setTimeout(() => {
|
||||
this.eventType = "";
|
||||
}, 500);
|
||||
}
|
||||
},
|
||||
remove() {
|
||||
this.$emit("remove", this.type.id);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
.type_set-box {
|
||||
width: 222px;
|
||||
background: #ffffff;
|
||||
margin-right: 15px;
|
||||
margin-bottom: 15px;
|
||||
.type_name {
|
||||
height: 66px;
|
||||
border: 1px solid #e9e9e9;
|
||||
border-bottom: none;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
line-height: 66px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
span {
|
||||
height: 24px;
|
||||
font-size: 15px;
|
||||
font-family: PingFangSC-Semibold, PingFang SC;
|
||||
font-weight: 500;
|
||||
color: #272829;
|
||||
line-height: 24px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 222px;
|
||||
display: inline-block;
|
||||
}
|
||||
.iconfont {
|
||||
font-size: 26px;
|
||||
}
|
||||
}
|
||||
.type_action {
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 222px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
background: #f7f7f7;
|
||||
border-radius: 0px 0px 2px 2px;
|
||||
border-top: none;
|
||||
border: 1px solid #e9e9e9;
|
||||
span {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
div {
|
||||
cursor: pointer;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
div:hover {
|
||||
color: #6c91f0;
|
||||
}
|
||||
}
|
||||
.divider {
|
||||
// position: relative;
|
||||
height: 14px;
|
||||
width: 1px;
|
||||
background: #e8e8e8;
|
||||
// left: 73px;
|
||||
// top: -23px;
|
||||
float: left;
|
||||
margin-left: 71px;
|
||||
margin-top: -22px;
|
||||
}
|
||||
.divider2 {
|
||||
// position: relative;
|
||||
// left: 146px;
|
||||
// top: -37px;
|
||||
height: 14px;
|
||||
width: 1px;
|
||||
background: #e8e8e8;
|
||||
float: left;
|
||||
margin-left: 147px;
|
||||
margin-top: -22px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<div>
|
||||
<ul class="public-upload-img fix">
|
||||
<li v-for="(item, index) in uploadList">
|
||||
<template v-if="item.status === 'finished'">
|
||||
<img :src="item.url" alt="" />
|
||||
<div class="upload-list-cover">
|
||||
<Icon type="ios-eye-outline" size="24" title="预览图片" @click.native="handleView(item.url)"></Icon>
|
||||
<Icon size="24" class="ml-10" title="删除图片" type="ios-trash-outline" @click.native="handleRemove(index)"></Icon>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Progress v-if="item.showProgress" :percent="item.percentage" class="mt-24" hide-info></Progress>
|
||||
</template>
|
||||
</li>
|
||||
<li class="add-li">
|
||||
<Upload
|
||||
ref="upload"
|
||||
:show-upload-list="false"
|
||||
:on-success="handleSuccess"
|
||||
:format="['jpg', 'jpeg', 'png', 'gif']"
|
||||
accept="image/gif,image/jpeg,image/jpg,image/png"
|
||||
:max-size="2048"
|
||||
:on-format-error="handleFormatError"
|
||||
:on-exceeded-size="handleMaxSize"
|
||||
:default-file-list="defaultList"
|
||||
type="drag"
|
||||
:action="uploadUrl"
|
||||
>
|
||||
<div class="add-box">
|
||||
<Icon type="ios-add" size="50"></Icon>
|
||||
</div>
|
||||
</Upload>
|
||||
</li>
|
||||
</ul>
|
||||
<Modal title="图片预览" v-model="visible" footer-hide>
|
||||
<img :src="imgName" v-if="visible" style="width: 100%" />
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
baseUrl: { type: String, default: "" },
|
||||
imgList: { type: Array, default: [] },
|
||||
uploadUrl: { type: String, default: "" },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
imgName: "",
|
||||
visible: false,
|
||||
uploadList: [],
|
||||
defaultList: [],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
let arr = [];
|
||||
|
||||
this.imgList.forEach(element => {
|
||||
arr.push({
|
||||
name: "",
|
||||
url: this.baseUrl + element,
|
||||
});
|
||||
});
|
||||
this.defaultList = arr;
|
||||
},
|
||||
mounted() {
|
||||
console.log(this.$refs.upload.fileList);
|
||||
this.uploadList = this.$refs.upload.fileList;
|
||||
},
|
||||
methods: {
|
||||
handleView(name) {
|
||||
this.imgName = name;
|
||||
this.visible = true;
|
||||
},
|
||||
handleRemove(index) {
|
||||
this.$refs.upload.fileList.splice(index, 1);
|
||||
this.imgList.splice(index, 1);
|
||||
},
|
||||
handleSuccess(res, file) {
|
||||
console.log(res, file);
|
||||
file.url = this.baseUrl + res.data;
|
||||
this.imgList.push(res.data);
|
||||
},
|
||||
handleFormatError(file) {
|
||||
console.error(file);
|
||||
},
|
||||
handleMaxSize(file) {
|
||||
this.$Notice.warning({
|
||||
title: "图片过大",
|
||||
desc: "图片最大上传大小为20M.",
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -0,0 +1,456 @@
|
||||
<template>
|
||||
<Modal v-model="modal" title="选择用户" width="720px" :mask-closable="false" :closable="false">
|
||||
<Tabs class="tabs-panel" type="card" v-if="firstTabIndex && firstTabIndex.length > 1" v-model="firstTabIndex" @on-click="firstTabChange">
|
||||
<TabPane v-for="(item, index) in firstTabData" :label="item" :name="index + ''"></TabPane>
|
||||
</Tabs>
|
||||
<AutoComplete @on-search="handleSearch" @on-select="handleSelect" placeholder="输入名字搜索" v-model="searchTreeName" :clearable="true" class="auto-box">
|
||||
<Option v-for="item in currentFlatten" :value="item.name">
|
||||
<span>{{ item.name }}</span>
|
||||
<span class="fr info">{{ item.group }}</span>
|
||||
</Option>
|
||||
</AutoComplete>
|
||||
<div class="tree-wrap fix">
|
||||
<div class="tree-panel fl">
|
||||
<ul class="tree-tab-ul fix">
|
||||
<li
|
||||
@click="secondTabChange(index)"
|
||||
:style="{ width: 100 / secondTabData.length + '%' }"
|
||||
:class="{ active: index == secondTabIndex, fl: true }"
|
||||
v-for="(item, index) in secondTabData"
|
||||
>
|
||||
{{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tree-box">
|
||||
<div :id="ztreeDomId" class="ztree"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="arrow-box fl">
|
||||
<svg t="1626916477711" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10021" width="36" height="36">
|
||||
<path
|
||||
d="M138.935 256.078v511.844h63.42V256.078h-63.42z m126.842 0v511.844h127.215V256.078H265.777zM885.064 512L583.254 64.323v191.755H456.414v511.844h126.842v191.755L885.064 512z"
|
||||
p-id="10022"
|
||||
fill="#2d8cf0"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="user-panel fr">
|
||||
<div class="title-box fix">
|
||||
<Checkbox @on-change="checkAllUser" v-model="isCheckUserAll">全选</Checkbox>
|
||||
<div class="fr">{{ tempUserList.length }}</div>
|
||||
<a href="javascript:;" @click="delCheckUser" v-if="tempUserList.findIndex(x => x.isCheck) > -1">删除选中</a>
|
||||
</div>
|
||||
<ul class="user-box">
|
||||
<li :class="{ active: item.isCheck }" v-for="(item, index) in tempUserList" @click="checkUserOne(item)">
|
||||
{{ item.name }}
|
||||
<span class="info">{{ item.group }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<i-Button type="primary" @click="submit">提交</i-Button>
|
||||
<i-Button @click="modal = false" style="margin-left: 8px">取消</i-Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
require("@public/libs/ztree/zTreeStyle.css");
|
||||
import "@public/libs/ztree/jquery.ztree.all.min.js";
|
||||
export default {
|
||||
props: {
|
||||
treeData: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
userids: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
ignoreIds: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
},
|
||||
model: {
|
||||
prop: "userids",
|
||||
event: "change",
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ztreeDomId: null,
|
||||
modal: false,
|
||||
isCheckUserAll: false,
|
||||
firstTabIndex: 0,
|
||||
secondTabIndex: 0,
|
||||
cacheMap: new Map(),
|
||||
currentTree: [],
|
||||
currentFlatten: [],
|
||||
searchTreeName: null,
|
||||
tempUserList: [],
|
||||
isDisabled: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
searchTreeName(val) {
|
||||
this.handleSearch(val);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
firstTabData() {
|
||||
if (this.treeData.length > 1) return this.treeData.map(x => x.name);
|
||||
else return [];
|
||||
},
|
||||
secondTabData() {
|
||||
if (this.treeData.length == 0) return [];
|
||||
return this.treeData[this.firstTabIndex].data.map(x => x.name);
|
||||
},
|
||||
currentTreeFlatten() {
|
||||
const flatten = (data, pid, pname) => {
|
||||
return data.reduce((arr, { id, name, children = [], type }) => arr.concat([{ id, name, pid, type, group: pname }], flatten(children, id, name)), []);
|
||||
};
|
||||
if (!this.currentTree) return [];
|
||||
var newArr = flatten(this.currentTree, 0, "");
|
||||
return newArr;
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.isDisabled = this.ignoreIds.length > 0;
|
||||
this.ztreeDomId = this.uuid();
|
||||
},
|
||||
methods: {
|
||||
show() {
|
||||
this.modal = true;
|
||||
this.firstTabChange("0");
|
||||
},
|
||||
firstTabChange(index) {
|
||||
this.firstTabIndex = index;
|
||||
this.secondTabChange(0);
|
||||
},
|
||||
secondTabChange(index) {
|
||||
const _this = this;
|
||||
if (index != 0 && this.secondTabIndex == index) return;
|
||||
this.secondTabIndex = index;
|
||||
this.changeEmpty();
|
||||
this.initTree();
|
||||
},
|
||||
handleSearch(query) {
|
||||
const _this = this;
|
||||
let arr = [],
|
||||
searchArr = this.currentTreeFlatten.filter(x => x.type == 2 && x.name.indexOf(query) != -1);
|
||||
for (const item of searchArr) {
|
||||
!arr.map(x => _this.getSplitId(x.id)).includes(_this.getSplitId(item.id)) && arr.push(item);
|
||||
}
|
||||
this.currentFlatten = arr;
|
||||
},
|
||||
handleSelect(query) {
|
||||
const _this = this;
|
||||
if (query.indexOf(",") != -1) query = query.split(",")[0];
|
||||
var treeObj = $.fn.zTree.getZTreeObj(this.ztreeDomId);
|
||||
var node = treeObj.getNodeByParam("name", query, null);
|
||||
if (!!node) treeObj.checkNode(node, true, true, true);
|
||||
},
|
||||
formatTree(tree, level = 0) {
|
||||
const _this = this;
|
||||
tree.forEach(element => {
|
||||
element.open = level == 0;
|
||||
element.type = 1;
|
||||
element.id = element.id + "," + element.pid;
|
||||
element.checked = false;
|
||||
if (typeof element.children !== "undefined" && element.children.length > 0) element.children = _this.formatTree(element.children, level + 1);
|
||||
else {
|
||||
element.type = 2;
|
||||
}
|
||||
});
|
||||
return tree;
|
||||
},
|
||||
initTree() {
|
||||
const _this = this;
|
||||
let first = _this.firstTabIndex,
|
||||
second = _this.secondTabIndex,
|
||||
cacheKey = first + "," + second,
|
||||
cacheMap = _this.cacheMap,
|
||||
tree = this.treeData[first].data[second].data;
|
||||
|
||||
if (!!tree && typeof tree === "function") {
|
||||
var cacheData = cacheMap.get(cacheKey);
|
||||
if (!cacheData) {
|
||||
tree().then(data => {
|
||||
cacheMap.set(cacheKey, data);
|
||||
_this.createTree(data, _this.ztreeDomId);
|
||||
});
|
||||
} else {
|
||||
_this.createTree(cacheData, _this.ztreeDomId);
|
||||
}
|
||||
} else {
|
||||
_this.createTree(tree, _this.ztreeDomId);
|
||||
}
|
||||
},
|
||||
createTree(_data, _domId) {
|
||||
const _this = this;
|
||||
var jtree = JSON.parse(JSON.stringify(_data));
|
||||
var ftree = _this.formatTree(jtree);
|
||||
_this.currentTree = ftree;
|
||||
//_this.tempUserList = JSON.parse(JSON.stringify(_this.userids));
|
||||
|
||||
let treeSetting = {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showIcon: false,
|
||||
},
|
||||
check: {
|
||||
enable: true,
|
||||
chkboxType: { Y: "ps", N: "ps" },
|
||||
},
|
||||
callback: {},
|
||||
};
|
||||
function formatUser(tree, checked) {
|
||||
const recursionCheckIds = tree => {
|
||||
let arrIds = [];
|
||||
for (const key in tree) {
|
||||
const element = tree[key];
|
||||
if (element.type == 2 && !element.chkDisabled) arrIds.push({ id: element.id, tid: element.tId });
|
||||
if (typeof element.children !== "undefined" && element.children) {
|
||||
var childIds = recursionCheckIds(element.children);
|
||||
arrIds = [...arrIds, ...childIds];
|
||||
}
|
||||
}
|
||||
return arrIds;
|
||||
};
|
||||
var checkIds = recursionCheckIds([tree]);
|
||||
var checkUserList = _this.currentTreeFlatten.filter(x => checkIds.map(x => x.id).includes(x.id));
|
||||
let checkUserArr = [];
|
||||
for (const element of checkUserList) {
|
||||
var findObj = checkIds.find(x => x.id == element.id);
|
||||
if (!!findObj && checkUserArr.findIndex(x => x.id == element.id) === -1 && _this.tempUserList.findIndex(x => x.id == element.id) === -1) {
|
||||
checkUserArr.push({ ...element, isCheck: false, tid: findObj.tid });
|
||||
}
|
||||
}
|
||||
if (checked) _this.tempUserList = _this.tempUserList.concat(checkUserArr);
|
||||
else {
|
||||
var ids = checkUserList.map(x => x.id);
|
||||
_this.tempUserList = _this.tempUserList.filter(x => !ids.includes(x.id));
|
||||
}
|
||||
}
|
||||
|
||||
//当禁止时,是否还显示在右侧
|
||||
var isCheckFormat = treeNode => {
|
||||
let id = _this.getSplitId(treeNode.id);
|
||||
return _this.ignoreIds.findIndex(x => x == id) === -1;
|
||||
};
|
||||
|
||||
treeSetting.callback.onClick = (event, treeId, treeNode, clickFlag) => {
|
||||
let check = treeNode.checked;
|
||||
let treeObj = $.fn.zTree.getZTreeObj(treeId);
|
||||
treeObj.checkNode(treeNode, !check, true);
|
||||
if (isCheckFormat(treeNode)) formatUser(treeNode, treeNode.checked);
|
||||
};
|
||||
treeSetting.callback.onCheck = (event, treeId, treeNode) => {
|
||||
if (isCheckFormat(treeNode)) formatUser(treeNode, treeNode.checked);
|
||||
};
|
||||
var treeObj = $.fn.zTree.init($("#" + _domId), treeSetting, ftree);
|
||||
//checkUser
|
||||
var nodes = treeObj.getNodesByFilter(x => _this.userids.includes(_this.getSplitId(x.id)));
|
||||
var arr = [];
|
||||
nodes.forEach(element => {
|
||||
var splitId = _this.getSplitId(element.id); //重复id只选择第一个
|
||||
if (!arr.includes(splitId)) treeObj.checkNode(element, true, true, true);
|
||||
arr.push(splitId);
|
||||
});
|
||||
|
||||
var ignorNodes = treeObj.getNodesByFilter(x => _this.ignoreIds.includes(_this.getSplitId(x.id)));
|
||||
ignorNodes.forEach(element => {
|
||||
treeObj.checkNode(element, true, true, true);
|
||||
treeObj.setChkDisabled(element, true);
|
||||
});
|
||||
},
|
||||
checkAllUser(check) {
|
||||
//全选用户
|
||||
const _this = this;
|
||||
_this.tempUserList.forEach(element => {
|
||||
element.isCheck = check;
|
||||
});
|
||||
},
|
||||
checkUserOne(item) {
|
||||
item.isCheck = !item.isCheck;
|
||||
let tlist = this.tempUserList;
|
||||
this.isCheckUserAll = tlist.length > 0 && tlist.filter(x => x.isCheck).length == tlist.length;
|
||||
},
|
||||
delCheckUser() {
|
||||
//删除选中用户
|
||||
const _this = this;
|
||||
let tlist = _this.tempUserList,
|
||||
delArr = [];
|
||||
for (const item of tlist) {
|
||||
item.isCheck && delArr.push(item);
|
||||
}
|
||||
var treeObj = $.fn.zTree.getZTreeObj(_this.ztreeDomId);
|
||||
delArr.forEach(element => {
|
||||
var node = treeObj.getNodeByTId(element.tid);
|
||||
treeObj.checkNode(node, false, true, true);
|
||||
});
|
||||
_this.isCheckUserAll = false;
|
||||
},
|
||||
changeEmpty() {
|
||||
this.tempUserList = [];
|
||||
this.searchTreeName = "";
|
||||
},
|
||||
submit() {
|
||||
const _this = this;
|
||||
let objArr = [],
|
||||
idsArr = this.tempUserList.map(x => _this.getSplitId(x.id));
|
||||
idsArr = Array.from(new Set(idsArr));
|
||||
this.$emit("change", idsArr);
|
||||
function delKey(obj, ...args) {
|
||||
args.forEach(v => {
|
||||
delete obj[v];
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
idsArr.forEach(element => {
|
||||
let findObj = _this.tempUserList.find(x => _this.getSplitId(x.id) == element);
|
||||
delKey(findObj, "id", "isCheck", "tid", "pid", "type");
|
||||
let item = { ...findObj, id: element };
|
||||
if (_this.isDisabled) item.disabled = this.userids.findIndex(x => x == element) !== -1;
|
||||
objArr.push(item);
|
||||
});
|
||||
|
||||
if (_this.isDisabled) {
|
||||
var treeObj = $.fn.zTree.getZTreeObj(_this.ztreeDomId);
|
||||
var nodes = treeObj.getNodesByFilter(x => x.chkDisabled);
|
||||
var disIds = nodes.map(x => _this.getSplitId(x.id));
|
||||
objArr.forEach(element => {
|
||||
element.disabled = disIds.findIndex(x => element.id == x) > -1;
|
||||
});
|
||||
}
|
||||
this.$emit("on-submit", objArr);
|
||||
this.modal = false;
|
||||
},
|
||||
getSplitId(strId) {
|
||||
if (typeof strId === "string" && strId.indexOf(",") != -1) return parseInt(strId.split(",")[0]);
|
||||
else return strId;
|
||||
},
|
||||
uuid() {
|
||||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
||||
var r = (Math.random() * 16) | 0,
|
||||
v = c == "x" ? r : (r & 0x3) | 0x8;
|
||||
return v.toString(16);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tree-wrap {
|
||||
height: 430px;
|
||||
position: relative;
|
||||
}
|
||||
.tree-panel {
|
||||
border: 1px solid #eee;
|
||||
width: 280px;
|
||||
height: 430px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.tree-tab-ul {
|
||||
li {
|
||||
background: #f7f7f7;
|
||||
border-bottom: 1px solid #eee;
|
||||
height: 34px;
|
||||
line-height: 34px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
li.active {
|
||||
background: #fff;
|
||||
color: #2d8cf0;
|
||||
border-bottom: none;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
.tree-box {
|
||||
padding: 4px 0;
|
||||
height: 394px;
|
||||
width: auto;
|
||||
overflow-y: auto;
|
||||
border: none;
|
||||
}
|
||||
.user-panel {
|
||||
border: 1px solid #eee;
|
||||
width: 280px;
|
||||
.title-box {
|
||||
background: #f7f7f7;
|
||||
height: 34px;
|
||||
line-height: 34px;
|
||||
padding: 0 12px;
|
||||
a {
|
||||
text-decoration: none;
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
.user-box {
|
||||
height: 396px;
|
||||
overflow-y: auto;
|
||||
li {
|
||||
line-height: 32px;
|
||||
padding-left: 12px;
|
||||
cursor: pointer;
|
||||
.info {
|
||||
float: right;
|
||||
margin-right: 12px;
|
||||
font-size: 12px;
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
li:hover {
|
||||
background: #f3f3f3;
|
||||
}
|
||||
li.active {
|
||||
background: #e4edf6;
|
||||
}
|
||||
}
|
||||
}
|
||||
.arrow-box {
|
||||
width: 128px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
margin-top: -17px;
|
||||
}
|
||||
|
||||
.auto-box {
|
||||
width: 200px;
|
||||
margin-bottom: 10px;
|
||||
.ivu-select-item .info {
|
||||
font-size: 12px;
|
||||
color: gray;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.ztree li {
|
||||
overflow: hidden;
|
||||
}
|
||||
.ztree li a {
|
||||
width: 100%;
|
||||
}
|
||||
.ztree li a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.ivu-auto-complete .ivu-select-dropdown-list {
|
||||
max-height: 310px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,157 @@
|
||||
import conf from "./hostConf.js";
|
||||
let BaseUrl = conf.serviceUrl;
|
||||
|
||||
export default {
|
||||
Base: {
|
||||
GetUserInfo: BaseUrl + "/api/GetUserInfo",
|
||||
GetUserMod: BaseUrl + "/api/GetUserMod",
|
||||
},
|
||||
BschClassSystem: {
|
||||
//年级树
|
||||
getGradeTree:BaseUrl + "/api/tree/getGradeTree",//获取年级树
|
||||
getClassTree:BaseUrl + "/api/tree/getClassTree",//获取班级树
|
||||
getTeaTree:BaseUrl + "/api/tree/getTeaTree",//获取教师树
|
||||
getGroupTree:BaseUrl + "/api/tree/getGroupTree",//获取全区树
|
||||
getHigherSchGradeTree:BaseUrl + "/api/tree/getHigherSchGradeTree",//获取高校年级树
|
||||
getHigherSchClassTree:BaseUrl + "/api/tree/getHigherSchClassTree",//获取高校班级树
|
||||
getgradeselect:BaseUrl + "/api/grade/select",//获取年级下拉
|
||||
getschclassselect:BaseUrl + "/api/schclass/select",//获取班级下拉
|
||||
getSchoolList:BaseUrl + "/api/tree/getSchoolList",//获取学校下拉
|
||||
getselectBySchId:BaseUrl + "/api/grade/selectBySchId",//通过学校ID获取年级下拉
|
||||
getselectBySchIdAndGradeId:BaseUrl + "/api/schclass/selectBySchIdAndGradeId",//通过学校ID、年级ID获取班级下拉
|
||||
getselectBySchsystemId:BaseUrl + "/api/grade/selectBySchsystemId",//通过学制ID获取年级下拉
|
||||
getTeacherTree:BaseUrl + "/api/tree/getTeacherTree",//获取教师选人树
|
||||
|
||||
//学制选择
|
||||
getschsystemlist: BaseUrl + "/api/schsystem/list",//获取学校绑定学制列表
|
||||
schsystemsave: BaseUrl + "/api/schsystem/save",//保存学制
|
||||
getschsystemselect: BaseUrl + "/api/schsystem/select",//获取选择的学制
|
||||
getType: BaseUrl + "/api/schsystem/getType",//获取学制类型
|
||||
|
||||
//时段设置
|
||||
getyeartermlist: BaseUrl + "/api/yearterm/list",//获取学年学期
|
||||
yeartermadd: BaseUrl + "/api/yearterm/add",//添加学年学期
|
||||
yeartermedit: BaseUrl + "/api/yearterm/edit",//编辑学年学期
|
||||
|
||||
//区域日志管理
|
||||
systemSearch: BaseUrl + "/api/log/systemSearch",//获取日志
|
||||
|
||||
//学校设置
|
||||
getcampuslist: BaseUrl + "/api/campus/list",//获取校区
|
||||
campussave: BaseUrl + "/api/campus/save",//保存校区
|
||||
campusdelete: BaseUrl + "/api/campus/delete/",//删除校区
|
||||
campussort: BaseUrl + "/api/campus/sort",//校区排序
|
||||
getcampusselect: BaseUrl + "/api/campus/select",//校区下拉
|
||||
|
||||
//系部设置
|
||||
getdivisionlist: BaseUrl + "/api/division/list",//获取系部列表
|
||||
divisionsave: BaseUrl + "/api/division/save",//保存系部
|
||||
divisiondelete: BaseUrl + "/api/division/delete/",//删除系部
|
||||
divisionsort: BaseUrl + "/api/division/sort",//系部排序
|
||||
getdivisionselect: BaseUrl + "/api/division/select",//系部下拉
|
||||
|
||||
//专业设置
|
||||
getmajorslist: BaseUrl + "/api/majors/list",//获取专业列表
|
||||
majorssave: BaseUrl + "/api/majors/save",//保存专业
|
||||
majorsdelete: BaseUrl + "/api/majors/delete/",//删除专业
|
||||
majorssort: BaseUrl + "/api/majors/sort",//专业排序
|
||||
getmajorsselect: BaseUrl + "/api/majors/select",//专业下拉
|
||||
|
||||
//课程管理
|
||||
getcourselist: BaseUrl + "/api/course/search",//获取课程列表
|
||||
coursesave: BaseUrl + "/api/course/save",//保存课程
|
||||
coursedelete: BaseUrl + "/api/course/delete/",//删除课程
|
||||
getcoursetypeselect: BaseUrl + "/api/course/typeSelect/",//课程类别下拉
|
||||
|
||||
//学科设置
|
||||
getsubjectlist: BaseUrl + "/api/subject/list",//获取学科列表
|
||||
subjectsave: BaseUrl + "/api/subject/save",//添加/编辑学科
|
||||
subjectsort: BaseUrl + "/api/subject/sort",//学科排序
|
||||
subjectdelete: BaseUrl + "/api/subject/delete/",//学科删除
|
||||
getsubjectselect: BaseUrl + "/api/subject/select",//获取学科下拉
|
||||
|
||||
//K12班级管理
|
||||
getsearcBaseSchClass: BaseUrl + "/api/schclass/searcBaseSchClass",//获取班级列表
|
||||
addBaseSchClass: BaseUrl + "/api/schclass/addBaseSchClass",//添加班级列表
|
||||
deleteBaseSchClass: BaseUrl + "/api/schclass/delete/",//删除班级列表
|
||||
editClassName: BaseUrl + "/api/schclass/editClassName",//编辑班级别名
|
||||
editClassFirstTeacher: BaseUrl + "/api/schclass/editClassFirstTeacher",//编辑班主任
|
||||
editClassSecondTeacher: BaseUrl + "/api/schclass/editClassSecondTeacher",//编辑副班主任
|
||||
editClassCampus: BaseUrl + "/api/schclass/editClassCampus",//编辑校区
|
||||
schclassdownloadTemplate: BaseUrl + "/api/schclass/downloadTemplate",//下载模版
|
||||
schclassImport: BaseUrl + "/api/schclass/importClasses",//导入班级
|
||||
|
||||
//高校班级管理
|
||||
getsearcHigherSchClass: BaseUrl + "/api/schclass/searcHigherSchClass",//获取班级列表
|
||||
saveHigherSchClass: BaseUrl + "/api/schclass/saveHigherSchClass",//添加班级列表
|
||||
deleteHigherSchClass: BaseUrl + "/api/schclass/HigherSchClassdelete/",//删除班级列表
|
||||
downloadHeightTemplate: BaseUrl + "/api/schclass/downloadHeightTemplate",//高校下载模版
|
||||
importHeightClasses: BaseUrl + "/api/schclass/importHeightClasses",//导入高校班级
|
||||
|
||||
//教师管理
|
||||
getteachersearch: BaseUrl + "/api/teacher/search",//获取教师列表
|
||||
getgroupteacherSelect: BaseUrl + "/api/teacher/groupSelect",//获取教师组下拉
|
||||
getgroupSelectBySchId: BaseUrl + "/api/teacher/groupSelectBySchId",//获取教师学科组下拉
|
||||
getteacherSelect: BaseUrl + "/api/teacher/select",//获取教师下拉
|
||||
teachersave: BaseUrl + "/api/teacher/save",//保存教师
|
||||
teacherdelete: BaseUrl + "/api/teacher/delete/",//删除教师
|
||||
teachersetStatus: BaseUrl + "/api/teacher/setStatus",//设置教师状态
|
||||
transferOut: BaseUrl + "/api/teacher/setTransferOut/",//设置移出教师
|
||||
moveGroup: BaseUrl + "/api/teacher/moveGroup",//移动教师
|
||||
setTransferIn: BaseUrl + "/api/teacher/setTransferIn",//教师转入
|
||||
transferOutSchSelect: BaseUrl + "/api/teacher/transferOutSchSelect",//教师转出学校下拉
|
||||
getsearchTransferOut: BaseUrl + "/api/teacher/searchTransferOut",//教师转出教师列表
|
||||
teacherdownloadTemplate: BaseUrl + "/api/teacher/downloadTemplate",//下载教师模版
|
||||
teacherImport: BaseUrl + "/api/teacher/Import",//教师导入
|
||||
|
||||
// 教师任教
|
||||
getteachssearch: BaseUrl + "/api/teachs/search",//获取任教列表
|
||||
teachssave: BaseUrl + "/api/teachs/save",//保存任教
|
||||
teachsdelete: BaseUrl + "/api/teachs/delete/",//删除任教
|
||||
delClassTeach: BaseUrl + "/api/teachs/delClassTeach",//删除班级任教
|
||||
teachsexport: BaseUrl + "/api/teachs/export",//导出任教
|
||||
TeachdownloadTemplate: BaseUrl + "/api/teachs/downloadTemplate",//导出任教模版
|
||||
importTeach: BaseUrl + "/api/teachs/importTeach",//导入任教
|
||||
getSchClassTeach: BaseUrl + "/api/teachs/getSchClassTeach",//通过班级ID获取任教
|
||||
|
||||
//教师分组管理
|
||||
getSchCustomGroup: BaseUrl + "/api/group/getSchCustomGroup",//获取教师分组列表
|
||||
saveSchCustomGroup: BaseUrl + "/api/group/saveSchCustomGroup",//保存教师分组
|
||||
saveMembers: BaseUrl + "/api/group/saveMembers",//设置组员
|
||||
setLeaders: BaseUrl + "/api/group/setLeaders",//设置组长
|
||||
deleteSchCustomGroup: BaseUrl + "/api/group/deleteSchCustomGroup",//删除分组
|
||||
GroupdownloadTemplate: BaseUrl + "/api/group/downloadTemplate",//导入分组模版
|
||||
importCustomGroup: BaseUrl + "/api/group/importCustomGroup",//导入分组
|
||||
|
||||
//k12学生管理
|
||||
getstudentsearch: BaseUrl + "/api/student/baseSchSearch",//获取学生列表
|
||||
studentsave: BaseUrl + "/api/student/save",//保存学生
|
||||
studentdelete: BaseUrl + "/api/student/delete/",//删除学生
|
||||
getstudentabnormal: BaseUrl + "/api/student/abnormal",//获取学生状态
|
||||
studenttransferClass: BaseUrl + "/api/student/transferClass",//学生调班
|
||||
studentsetAbnormalStatus: BaseUrl + "/api/student/setAbnormalStatus",//学生异动
|
||||
studenttransferOut: BaseUrl + "/api/student/setTransferOut/",//设置移出学生
|
||||
studenttransferOutSchSelect: BaseUrl + "/api/student/transferOutSchSelect",//学生转出学校下拉
|
||||
getstudentsearchTransferOut: BaseUrl + "/api/student/searchTransferOut",//学生转出列表
|
||||
studentsetTransferIn: BaseUrl + "/api/student/setTransferIn",//学生转入
|
||||
studentdownloadTemplate: BaseUrl + "/api/student/downloadTemplate",//下载学生导入模版
|
||||
importStudents: BaseUrl + "/api/student/importStudents",//学生导入
|
||||
studentClassNoTemplate: BaseUrl + "/api/student/studentClassNoTemplate",//下载学生学号导入模版
|
||||
importStudentClassNo: BaseUrl + "/api/student/importStudentClassNo",//学生学号导入
|
||||
searchSchClassStudent: BaseUrl + "/api/student/searchSchClassStudent",//通过班级ID获取学生
|
||||
|
||||
//高校学生管理
|
||||
gethigherSchSearch: BaseUrl + "/api/student/higherSchSearch",//获取学生列表
|
||||
|
||||
|
||||
// 学生异动管理
|
||||
getbaseSchAbnormalSearch: BaseUrl + "/api/student/baseSchAbnormalSearch",//获取K12学生异动列表
|
||||
gethigherSchAbnormalSearch: BaseUrl + "/api/student/higherSchAbnormalSearch",//获取高校学生异动列表
|
||||
|
||||
//日志管理
|
||||
getlogsearch: BaseUrl + "/api/log/search",//获取日志列表
|
||||
|
||||
//公共接口
|
||||
uploadFile: BaseUrl + "/api/uploadFile",//上传文件
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
let conf = {
|
||||
baseHost: "http://base.bestsch.com",
|
||||
ssoHost: "http://sso.bestsch.com",
|
||||
serviceUrl: "http://192.168.10.166:8087",
|
||||
fileHost:'http://base.bestsch.com/ClassroomMan/file',
|
||||
isLayoutOld: false
|
||||
// serviceUrl: "http://basedebug.bestsch.com/BschHome/",
|
||||
};
|
||||
|
||||
if (typeof window.conf !== "undefined") conf = window.conf;
|
||||
|
||||
export default conf;
|
||||
@@ -0,0 +1,251 @@
|
||||
<template>
|
||||
<div class="layout-wrap">
|
||||
<header class="header-container fix">
|
||||
<div class="fl align-middle icon-box">
|
||||
<div :class="['icon-btn', isPanel ? 'active' : '']" @click="showPanel">
|
||||
<svg width="22" height="22" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path d="M24 0.972656H0V24.9727H24V0.972656Z" fill="white" fill-opacity="0.01" />
|
||||
<path
|
||||
d="M9 2.97266H3C2.44772 2.97266 2 3.42037 2 3.97266V9.97266C2 10.5249 2.44772 10.9727 3 10.9727H9C9.55228 10.9727 10 10.5249 10 9.97266V3.97266C10 3.42037 9.55228 2.97266 9 2.97266Z"
|
||||
stroke="white"
|
||||
stroke-width="1.6"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M9 14.9727H3C2.44772 14.9727 2 15.4204 2 15.9727V21.9727C2 22.5249 2.44772 22.9727 3 22.9727H9C9.55228 22.9727 10 22.5249 10 21.9727V15.9727C10 15.4204 9.55228 14.9727 9 14.9727Z"
|
||||
stroke="white"
|
||||
stroke-width="1.6"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M21 2.97266H15C14.4477 2.97266 14 3.42037 14 3.97266V9.97266C14 10.5249 14.4477 10.9727 15 10.9727H21C21.5523 10.9727 22 10.5249 22 9.97266V3.97266C22 3.42037 21.5523 2.97266 21 2.97266Z"
|
||||
stroke="white"
|
||||
stroke-width="1.6"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M14 14.9727H22"
|
||||
stroke="white"
|
||||
stroke-width="1.6"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M18 18.9727H22"
|
||||
stroke="white"
|
||||
stroke-width="1.6"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M14 22.9727H22"
|
||||
stroke="white"
|
||||
stroke-width="1.6"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="24" height="24" fill="white" transform="translate(0 0.972656)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="delimiter fl align-middle"></div>
|
||||
<h4 class="fl align-middle">{{ appName }}</h4>
|
||||
<div class="school-bg"></div>
|
||||
<div class="header-aside fr">
|
||||
<img :src="userInfo.avatar" class="fl align-middle" @click="linkUserInfo" />
|
||||
<a class="name fl align-middle text-ellipsis" href="javascript:void(0);" @click="linkUserInfo">
|
||||
{{ userInfo.name }}
|
||||
</a>
|
||||
<div class="delimiter fl align-middle"></div>
|
||||
<a href="javascript:;" @click="logout" class="logout fl align-middle" title="退出登陆">
|
||||
<svg
|
||||
t="1615536538850"
|
||||
viewBox="0 0 1024 1024"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
p-id="3048"
|
||||
width="18"
|
||||
height="18"
|
||||
>
|
||||
<path
|
||||
d="M554.666667 426.666667a42.666667 42.666667 0 0 1-85.333334 0V128a42.666667 42.666667 0 0 1 85.333334 0v298.666667z m101.973333-133.376a42.666667 42.666667 0 0 1 41.429333-74.581334 384 384 0 1 1-372.138666 0 42.666667 42.666667 0 0 1 41.386666 74.581334 298.666667 298.666667 0 1 0 289.365334 0z"
|
||||
p-id="3049"
|
||||
fill="#ffffff"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="left-menu" v-if="!isAlone">
|
||||
<div class="menu-top-box"></div>
|
||||
<ul>
|
||||
<li
|
||||
:class="item.page == currPath ? 'active' : ''"
|
||||
v-for="(item, index) in modList"
|
||||
:key="'menu_li_' + index"
|
||||
>
|
||||
<a href="javascript:;" @click="linkMenu(item.page)">
|
||||
<div v-if="item.icon" :class="['icon-box fl', item.icon]"></div>
|
||||
<div v-else class="icon-box fl">
|
||||
<svg
|
||||
t="1615860353141"
|
||||
class="icon"
|
||||
viewBox="0 0 1024 1024"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
p-id="6624"
|
||||
width="14"
|
||||
height="14"
|
||||
>
|
||||
<path
|
||||
d="M0 102.4h307.2v307.2H0zM0 614.4h307.2v307.2H0zM409.6 102.4h614.4v102.4H409.6zM409.6 307.2h614.4v102.4H409.6zM409.6 614.4h614.4v102.4H409.6zM409.6 819.2h614.4v102.4H409.6z"
|
||||
p-id="6625"
|
||||
fill="#656667"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
{{ item.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clear-box"></div>
|
||||
</div>
|
||||
<template v-if="!isAlone">
|
||||
<div class="path-nav">
|
||||
<Breadcrumb separator=">">
|
||||
<a :href="baseHost + '/BschHome/front/index.html'">
|
||||
<BreadcrumbItem>
|
||||
<Icon type="ios-home-outline" size="14"></Icon>
|
||||
首页
|
||||
</BreadcrumbItem>
|
||||
</a>
|
||||
<BreadcrumbItem to="/">{{ appName }}</BreadcrumbItem>
|
||||
<BreadcrumbItem v-if="typeof navPath === 'string'">{{ navPath }}</BreadcrumbItem>
|
||||
<template v-else v-for="(item, index) in navPath">
|
||||
<BreadcrumbItem v-if="index != navPath.length - 1" :to="item.page">
|
||||
{{ item.name }}
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbItem v-else>{{ item.name }}</BreadcrumbItem>
|
||||
</template>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
<!-- <div class="path-nav" v-else>
|
||||
{{ navPath }}
|
||||
</div> -->
|
||||
</template>
|
||||
|
||||
<transition name="fade_apps">
|
||||
<div class="app-panel" ref="appPanel" v-if="isPanel">
|
||||
<div class="tips-box"></div>
|
||||
<ul class="fix">
|
||||
<li class="fl" v-for="item in appList">
|
||||
<a :href="item.url" target="_bank" rel="noopener noreferrer">
|
||||
<div class="icon-box">
|
||||
<img :src="item.icon" alt="" />
|
||||
</div>
|
||||
<p class="text-ellipsis">{{ item.name }}</p>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="link-panel">
|
||||
<a :href="baseHost + '/BschHome/front/index.html#/apps'" target="_bank" rel="noopener noreferrer">
|
||||
全部应用
|
||||
<i>→</i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ["reload"],
|
||||
props: {
|
||||
layoutData: {
|
||||
appName: String,
|
||||
appList: Array,
|
||||
modList: Array,
|
||||
userInfo: Object,
|
||||
ssoHost: String,
|
||||
baseHost: String,
|
||||
isAlone: Boolean, //是否只有一个选项卡
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
color: "#fff",
|
||||
isPanel: false,
|
||||
themeColor: [],
|
||||
currPath: "/layout",
|
||||
navPath: "默认列表",
|
||||
};
|
||||
},
|
||||
created() {
|
||||
const _this = this;
|
||||
for (const key in _this.layoutData) _this[key] = _this.layoutData[key];
|
||||
_this.routeChange(_this.$route); //初次加载时手动触发route的change
|
||||
this.$watch("$route", _this.routeChange);
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
showPanel() {
|
||||
const _this = this;
|
||||
if (_this.appList.length == 0) {
|
||||
_this.$Message.info("暂无常用应用!");
|
||||
return;
|
||||
}
|
||||
_this.isPanel = false;
|
||||
setTimeout(() => {
|
||||
_this.isPanel = true;
|
||||
setTimeout(showPanel, 0);
|
||||
}, 0);
|
||||
var showPanel = () => {
|
||||
_this.$refs["appPanel"].onclick = e => e.stopPropagation();
|
||||
document.onclick = () => (_this.isPanel = false);
|
||||
};
|
||||
},
|
||||
routeChange(router) {
|
||||
const _this = this;
|
||||
window.document.title = router.meta.title || "弘育云平台";
|
||||
let currentMod = router.meta.modId;
|
||||
//时间有限,仅支持一层.暂时写死,有需求再改
|
||||
_this.modList.forEach(element => {
|
||||
let childIndex = element.children.findIndex(x => x.modId == currentMod);
|
||||
if (currentMod == element.modId || childIndex > -1) {
|
||||
_this.currPath = element.page;
|
||||
if (childIndex > -1) {
|
||||
let navArr = [];
|
||||
navArr.push({ name: element.name, page: element.page });
|
||||
navArr.push({
|
||||
name: element.children[childIndex].name,
|
||||
page: element.children[childIndex].page,
|
||||
});
|
||||
_this.navPath = navArr;
|
||||
} else _this.navPath = element.name;
|
||||
}
|
||||
});
|
||||
},
|
||||
linkMenu(page) {
|
||||
const path = this.$route.path;
|
||||
if (page === path) this.reload();
|
||||
else this.$router.push(page);
|
||||
},
|
||||
linkUserInfo() {
|
||||
top.location.href = this.baseHost + "/v/userinfo";
|
||||
},
|
||||
logout() {
|
||||
let url = window.location.href;
|
||||
url = "/logout?service=" + url;
|
||||
top.location.href = this.ssoHost + url;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,305 @@
|
||||
<template>
|
||||
<div class="layout-wrap">
|
||||
<header class="header-container fix">
|
||||
<div class="fl align-middle icon-box">
|
||||
<div
|
||||
:class="['icon-btn', isPanel ? 'active' : '']"
|
||||
@click="showPanel"
|
||||
>
|
||||
<svg
|
||||
t="1615518122113"
|
||||
class="icon"
|
||||
viewBox="0 0 1024 1024"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
p-id="1276"
|
||||
width="18"
|
||||
height="18"
|
||||
>
|
||||
<path
|
||||
d="M710.54933333 68.11733334a64 64 0 0 1 90.496 0l165.504 165.504a64 64 0 0 1 0 90.496l-165.504 165.504a64 64 0 0 1-90.496 0l-165.504-165.504a64 64 0 0 1 0-90.496l165.504-165.504zM165.33333333 69.33333334a96 96 0 0 0-96 96v224a96 96 0 0 0 96 96h224a96 96 0 0 0 96-96V165.33333334a96 96 0 0 0-96-96H165.33333333zM165.33333333 549.33333334a96 96 0 0 0-96 96v224a96 96 0 0 0 96 96h224a96 96 0 0 0 96-96v-224a96 96 0 0 0-96-96H165.33333333zM645.33333333 549.33333334a96 96 0 0 0-96 96v224a96 96 0 0 0 96 96h224a96 96 0 0 0 96-96v-224a96 96 0 0 0-96-96h-224z"
|
||||
p-id="1277"
|
||||
:fill="color"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="delimiter fl align-middle"></div>
|
||||
<h4 class="fl align-middle">{{ appName }}</h4>
|
||||
<div class="school-bg"></div>
|
||||
<div class="header-aside fr">
|
||||
<img
|
||||
:src="userInfo.avatar"
|
||||
class="fl align-middle"
|
||||
@click="linkUserInfo"
|
||||
/>
|
||||
<a
|
||||
class="name fl align-middle text-ellipsis"
|
||||
href="javascript:void(0);"
|
||||
@click="linkUserInfo"
|
||||
>{{ userInfo.name }}</a
|
||||
>
|
||||
<div class="delimiter fl align-middle"></div>
|
||||
<a
|
||||
href="javascript:;"
|
||||
@click="logout"
|
||||
class="logout fl align-middle"
|
||||
title="退出登陆"
|
||||
>
|
||||
<svg
|
||||
t="1615536538850"
|
||||
viewBox="0 0 1024 1024"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
p-id="3048"
|
||||
width="18"
|
||||
height="18"
|
||||
>
|
||||
<path
|
||||
d="M554.666667 426.666667a42.666667 42.666667 0 0 1-85.333334 0V128a42.666667 42.666667 0 0 1 85.333334 0v298.666667z m101.973333-133.376a42.666667 42.666667 0 0 1 41.429333-74.581334 384 384 0 1 1-372.138666 0 42.666667 42.666667 0 0 1 41.386666 74.581334 298.666667 298.666667 0 1 0 289.365334 0z"
|
||||
p-id="3049"
|
||||
fill="#ffffff"
|
||||
></path>
|
||||
<!-- d5defe -->
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="left-menu" v-if="!isAlone">
|
||||
<div class="menu-top-box"></div>
|
||||
<ul>
|
||||
<template v-for="(item, index) in modArr">
|
||||
<template v-if="item.children && item.children.length > 0">
|
||||
<li>
|
||||
<a href="javascript:;" @click="childChange(index)">
|
||||
<i
|
||||
:class="
|
||||
item.childState
|
||||
? 'arrow-down'
|
||||
: 'arrow-up'
|
||||
"
|
||||
></i>
|
||||
<div
|
||||
v-if="item.icon"
|
||||
:class="['icon-box fl', item.icon]"
|
||||
></div>
|
||||
<div v-else class="icon-box fl">
|
||||
<svg
|
||||
t="1615860353141"
|
||||
class="icon"
|
||||
viewBox="0 0 1024 1024"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
p-id="6624"
|
||||
width="14"
|
||||
height="14"
|
||||
>
|
||||
<path
|
||||
d="M0 102.4h307.2v307.2H0zM0 614.4h307.2v307.2H0zM409.6 102.4h614.4v102.4H409.6zM409.6 307.2h614.4v102.4H409.6zM409.6 614.4h614.4v102.4H409.6zM409.6 819.2h614.4v102.4H409.6z"
|
||||
p-id="6625"
|
||||
fill="#656667"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
{{ item.name }}
|
||||
</a>
|
||||
</li>
|
||||
<transition name="fade_child_ul">
|
||||
<div
|
||||
class="child-item-wrap"
|
||||
v-show="item.childState"
|
||||
>
|
||||
<li
|
||||
:class="
|
||||
citem.page == currPath
|
||||
? 'active child-item'
|
||||
: 'child-item'
|
||||
"
|
||||
v-for="citem in item.children"
|
||||
>
|
||||
<a
|
||||
href="javascript:;"
|
||||
@click="linkMenu(citem.page)"
|
||||
>
|
||||
{{ citem.name }}
|
||||
</a>
|
||||
</li>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
<li
|
||||
v-else
|
||||
:class="item.page == currPath ? 'active' : ''"
|
||||
:key="'menu_li_' + index"
|
||||
>
|
||||
<a href="javascript:;" @click="linkMenu(item.page)">
|
||||
<div
|
||||
v-if="item.icon"
|
||||
:class="['icon-box fl', item.icon]"
|
||||
></div>
|
||||
<div v-else class="icon-box fl">
|
||||
<svg
|
||||
t="1615860353141"
|
||||
class="icon"
|
||||
viewBox="0 0 1024 1024"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
p-id="6624"
|
||||
width="14"
|
||||
height="14"
|
||||
>
|
||||
<path
|
||||
d="M0 102.4h307.2v307.2H0zM0 614.4h307.2v307.2H0zM409.6 102.4h614.4v102.4H409.6zM409.6 307.2h614.4v102.4H409.6zM409.6 614.4h614.4v102.4H409.6zM409.6 819.2h614.4v102.4H409.6z"
|
||||
p-id="6625"
|
||||
fill="#656667"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
{{ item.name }}
|
||||
</a>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
<div class="clear-box"></div>
|
||||
</div>
|
||||
<template v-if="!isAlone">
|
||||
<div
|
||||
class="path-nav"
|
||||
v-if="navPath instanceof Array && navPath.length > 1"
|
||||
>
|
||||
<Breadcrumb separator=">">
|
||||
<template v-for="(item, index) in navPath">
|
||||
<BreadcrumbItem>{{ item.name }}</BreadcrumbItem>
|
||||
</template>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
<div class="path-nav" v-else>
|
||||
{{ navPath }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<transition name="fade_apps">
|
||||
<div class="app-panel" ref="appPanel" v-if="isPanel">
|
||||
<div class="tips-box"></div>
|
||||
<ul class="fix">
|
||||
<li class="fl" v-for="item in appList">
|
||||
<a
|
||||
:href="item.url"
|
||||
target="_bank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<div class="icon-box">
|
||||
<img :src="item.icon" alt="" />
|
||||
</div>
|
||||
<p class="text-ellipsis">{{ item.name }}</p>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="link-panel">
|
||||
<a
|
||||
:href="baseHost + '/BschHome/front/index.html#/apps'"
|
||||
target="_bank"
|
||||
rel="noopener noreferrer"
|
||||
>全部应用<i>→</i></a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ["reload"],
|
||||
props: {
|
||||
layoutData: {
|
||||
appName: String,
|
||||
appList: Array,
|
||||
modList: Array,
|
||||
userInfo: Object,
|
||||
ssoHost: String,
|
||||
baseHost: String,
|
||||
isAlone: Boolean, //是否只有一个选项卡
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
color: "#fff",
|
||||
isPanel: false,
|
||||
themeColor: [],
|
||||
currPath: "",
|
||||
navPath: null,
|
||||
modArr: [],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
const _this = this;
|
||||
for (const key in _this.layoutData) _this[key] = _this.layoutData[key];
|
||||
_this.routeChange(_this.$route); //初次加载时手动触发route的change
|
||||
this.$watch("$route", _this.routeChange);
|
||||
this.modList.forEach((element) => {
|
||||
element.childState = true;
|
||||
this.modArr.push(element);
|
||||
});
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
showPanel() {
|
||||
const _this = this;
|
||||
if (_this.appList.length == 0) {
|
||||
_this.$Message.info("暂无常用应用!");
|
||||
return;
|
||||
}
|
||||
_this.isPanel = false;
|
||||
setTimeout(() => {
|
||||
_this.isPanel = true;
|
||||
setTimeout(showPanel, 0);
|
||||
}, 0);
|
||||
var showPanel = () => {
|
||||
_this.$refs["appPanel"].onclick = (e) => e.stopPropagation();
|
||||
document.onclick = () => (_this.isPanel = false);
|
||||
};
|
||||
},
|
||||
routeChange(router) {
|
||||
const _this = this;
|
||||
window.document.title = router.meta.title || "弘育云平台";
|
||||
let currentMod = router.meta.modId;
|
||||
_this.currPath = router.path;
|
||||
//时间有限,仅支持一层.暂时写死,有需求再改
|
||||
_this.modList.forEach((element) => {
|
||||
let childIndex = element.children.findIndex(
|
||||
(x) => x.modId == currentMod
|
||||
);
|
||||
if (currentMod == element.modId || childIndex > -1) {
|
||||
if (childIndex > -1) {
|
||||
let navArr = [];
|
||||
navArr.push({ name: element.name, page: element.page });
|
||||
navArr.push({
|
||||
name: element.children[childIndex].name,
|
||||
page: element.children[childIndex].page,
|
||||
});
|
||||
_this.navPath = navArr;
|
||||
} else _this.navPath = element.name;
|
||||
}
|
||||
});
|
||||
},
|
||||
linkMenu(page) {
|
||||
const path = this.$route.path;
|
||||
if (page === path) this.reload();
|
||||
else this.$router.push(page);
|
||||
},
|
||||
linkUserInfo() {
|
||||
top.location.href = this.baseHost + "/v/userinfo";
|
||||
},
|
||||
childChange(index) {
|
||||
this.modArr[index].childState = !this.modArr[index].childState;
|
||||
},
|
||||
logout() {
|
||||
let url = window.location.href;
|
||||
url = "/logout?service=" + url;
|
||||
top.location.href = this.ssoHost + url;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,263 @@
|
||||
<template>
|
||||
<div class="layout-wrap">
|
||||
<header class="header-container fix">
|
||||
<div class="fl align-middle icon-box">
|
||||
<div title="常用应用" :class="['icon-btn', isPanel ? 'active' : '']" @click="showPanel">
|
||||
<i class="iconfont icon-apps"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="delimiter fl align-middle"></div>
|
||||
<h4 class="fl align-middle">{{ appName }}</h4>
|
||||
<div class="school-bg"></div>
|
||||
<div class="header-aside fr">
|
||||
<img :src="userInfo.avatar" class="fl align-middle" @click="linkUserInfo" />
|
||||
<a class="name fl align-middle text-ellipsis" href="javascript:void(0);" @click="linkUserInfo">
|
||||
{{ userInfo.name }}
|
||||
</a>
|
||||
<div class="delimiter fl align-middle"></div>
|
||||
<a href=" " @click="logout" class="logout fl align-middle" title="退出登陆">
|
||||
<i class="iconfont icon-logout"></i>
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="left-menu" v-if="!isAlone">
|
||||
<div class="menu-top-box"></div>
|
||||
<ul>
|
||||
<template v-for="(item, index) in modArr">
|
||||
<template v-if="item.children && item.children.length > 0">
|
||||
<li>
|
||||
<a href="javascript:;" @click="childChange(index)">
|
||||
<i :class="item.childState ? 'arrow-down' : 'arrow-up'"></i>
|
||||
<div v-if="item.icon" :class="['icon-box fl', item.icon]"></div>
|
||||
<div v-else class="icon-box fl">
|
||||
<svg
|
||||
t="1615860353141"
|
||||
class="icon"
|
||||
viewBox="0 0 1024 1024"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
p-id="6624"
|
||||
width="14"
|
||||
height="14"
|
||||
>
|
||||
<path
|
||||
d="M0 102.4h307.2v307.2H0zM0 614.4h307.2v307.2H0zM409.6 102.4h614.4v102.4H409.6zM409.6 307.2h614.4v102.4H409.6zM409.6 614.4h614.4v102.4H409.6zM409.6 819.2h614.4v102.4H409.6z"
|
||||
p-id="6625"
|
||||
fill="#656667"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
{{ item.name }}
|
||||
</a>
|
||||
</li>
|
||||
<transition name="fade_child_ul">
|
||||
<div class="child-item-wrap" v-show="item.childState">
|
||||
<li
|
||||
:class="citem.page == currPath ? 'active child-item' : 'child-item'"
|
||||
v-for="citem in item.children"
|
||||
>
|
||||
<a href="javascript:;" @click="linkMenu(citem.page)">
|
||||
{{ citem.name }}
|
||||
</a>
|
||||
</li>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
<li v-else :class="item.page == currPath ? 'active' : ''" :key="'menu_li_' + index">
|
||||
<a href="javascript:;" @click="linkMenu(item.page)">
|
||||
<div v-if="item.icon" :class="['icon-box fl', item.icon]"></div>
|
||||
<div v-else class="icon-box fl">
|
||||
<svg
|
||||
t="1615860353141"
|
||||
class="icon"
|
||||
viewBox="0 0 1024 1024"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
p-id="6624"
|
||||
width="14"
|
||||
height="14"
|
||||
>
|
||||
<path
|
||||
d="M0 102.4h307.2v307.2H0zM0 614.4h307.2v307.2H0zM409.6 102.4h614.4v102.4H409.6zM409.6 307.2h614.4v102.4H409.6zM409.6 614.4h614.4v102.4H409.6zM409.6 819.2h614.4v102.4H409.6z"
|
||||
p-id="6625"
|
||||
fill="#656667"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
{{ item.name }}
|
||||
</a>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
<div class="clear-box"></div>
|
||||
</div>
|
||||
<div class="path-nav" v-if="!isAlone">
|
||||
<Breadcrumb separator=">">
|
||||
<a :href="baseHost + '/BschHome/front/index.html'">
|
||||
<BreadcrumbItem>
|
||||
<i class="iconfont icon-category"></i>
|
||||
首页
|
||||
</BreadcrumbItem>
|
||||
</a>
|
||||
<BreadcrumbItem to="/">{{ appName }}</BreadcrumbItem>
|
||||
<BreadcrumbItem v-if="typeof navPath == 'string'">{{ navPath }}</BreadcrumbItem>
|
||||
<template v-else v-for="(item, index) in navPath">
|
||||
<BreadcrumbItem v-if="index != navPath.length - 1" :to="item.page">{{ item.name }}</BreadcrumbItem>
|
||||
<BreadcrumbItem v-else>{{ item.name }}</BreadcrumbItem>
|
||||
</template>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
|
||||
<transition name="fade_apps">
|
||||
<div class="app-panel" ref="appPanel" v-if="isPanel">
|
||||
<div class="tips-box"></div>
|
||||
<ul class="fix">
|
||||
<li class="fl" v-for="item in appList">
|
||||
<a :href="item.url" target="_bank" rel="noopener noreferrer">
|
||||
<div class="icon-box">
|
||||
<img :src="item.icon" alt="" />
|
||||
</div>
|
||||
<p class="text-ellipsis">{{ item.name }}</p>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="link-panel">
|
||||
<a :href="baseHost + '/BschHome/front/index.html#/apps'" target="_bank" rel="noopener noreferrer">
|
||||
全部应用
|
||||
<i>→</i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ["reload"],
|
||||
props: {
|
||||
layoutData: {
|
||||
appName: String,
|
||||
appList: Array,
|
||||
modList: Array,
|
||||
userInfo: Object,
|
||||
ssoHost: String,
|
||||
baseHost: String,
|
||||
isAlone: Boolean //是否只有一个选项卡
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
color: "#fff",
|
||||
isPanel: false,
|
||||
themeColor: [],
|
||||
currPath: "",
|
||||
navPath: null,
|
||||
modArr: [],
|
||||
menuArr: []
|
||||
};
|
||||
},
|
||||
created() {
|
||||
const _this = this;
|
||||
for (const key in _this.layoutData) _this[key] = _this.layoutData[key];
|
||||
this.menuArr = this.flaten(this.modList);
|
||||
_this.routeChange(_this.$route); //初次加载时手动触发route的change
|
||||
this.$watch("$route", _this.routeChange);
|
||||
this.modList.forEach(element => {
|
||||
element.childState = true; //此处修改结点状态,默认打开
|
||||
this.modArr.push(element);
|
||||
});
|
||||
|
||||
this.$bus.$on("setNavPath", arr => (_this.navPath = arr));
|
||||
this.$bus.$on("setMenuPath", modId => {
|
||||
let find = this.menuArr.find(x => x.modId == modId);
|
||||
!!find && (this.currPath = find.page);
|
||||
});
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
showPanel() {
|
||||
const _this = this;
|
||||
if (_this.appList.length == 0) {
|
||||
_this.$Message.info("暂无常用应用!");
|
||||
return;
|
||||
}
|
||||
_this.isPanel = false;
|
||||
setTimeout(() => {
|
||||
_this.isPanel = true;
|
||||
setTimeout(showPanel, 0);
|
||||
}, 0);
|
||||
var showPanel = () => {
|
||||
_this.$refs["appPanel"].onclick = e => e.stopPropagation();
|
||||
document.onclick = () => (_this.isPanel = false);
|
||||
};
|
||||
},
|
||||
routeChange(router) {
|
||||
const _this = this;
|
||||
let { modId, title, parentId: routerPId } = router.meta,
|
||||
navArr = [];
|
||||
window.document.title = title || "弘育云平台";
|
||||
var find = this.menuArr.find(x => x.modId == modId);
|
||||
if (!find) {
|
||||
let parentFind = this.menuArr.find(x => x.modId == routerPId);
|
||||
if (!parentFind) {
|
||||
// this.$router.push("/");
|
||||
// throw "路由错误!";
|
||||
let newmenuArr = this.menuArr.filter(x => x.pid>0);
|
||||
if(newmenuArr.length>0){
|
||||
if(newmenuArr.findIndex(x => x.page == this.$route.path)==-1){
|
||||
this.$router.push(newmenuArr[0].page);
|
||||
}
|
||||
}else{
|
||||
if(this.menuArr.findIndex(x => x.page == this.$route.path)==-1){
|
||||
this.$router.push(this.menuArr[0].page);
|
||||
}
|
||||
}
|
||||
parentFind=this.menuArr[0];
|
||||
}
|
||||
find = parentFind;
|
||||
setTimeout(() => {
|
||||
this.navPath.push({ name: title });
|
||||
}, 0);
|
||||
}
|
||||
let { name, page, pid } = find;
|
||||
this.currPath = page;
|
||||
let pfind = this.menuArr.find(x => x.id == pid);
|
||||
if (!!pfind) {
|
||||
navArr.push({ name: pfind.name });
|
||||
}
|
||||
navArr.push({ name, page });
|
||||
this.navPath = navArr;
|
||||
},
|
||||
linkMenu(page) {
|
||||
const path = this.$route.path;
|
||||
if (page === path) this.reload();
|
||||
else this.$router.push(page);
|
||||
},
|
||||
linkUserInfo() {
|
||||
top.location.href = this.baseHost + "/v/userinfo";
|
||||
},
|
||||
childChange(index) {
|
||||
this.modArr[index].childState = !this.modArr[index].childState;
|
||||
},
|
||||
|
||||
logout() {
|
||||
let url = window.location.href;
|
||||
url = "/logout?service=" + url;
|
||||
top.location.href = this.ssoHost + url;
|
||||
},
|
||||
flaten(tree, pid = 0) {
|
||||
var arr = [];
|
||||
tree.forEach(element => {
|
||||
let { id, name, page, modId } = element;
|
||||
arr.push({ id, name, page, modId, pid });
|
||||
if (element.children) {
|
||||
arr.push(...this.flaten(element.children, id));
|
||||
}
|
||||
});
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,306 @@
|
||||
<template>
|
||||
<div class="layout_old">
|
||||
<!-- 头部 -->
|
||||
<header class="header">
|
||||
<div class="header-logo">
|
||||
<div class="header-logo-title">
|
||||
<img :src="logoUrl" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-aside">
|
||||
<div class="aside-box clearfix">
|
||||
<p>
|
||||
你好,
|
||||
<a>{{ username }}</a>
|
||||
</p>
|
||||
<p class="aside-btn-list">
|
||||
<Tooltip content="个人信息" placement="bottom-start">
|
||||
<Button type="ghost" icon="android-happy" @click="linkUser()"></Button>
|
||||
</Tooltip>
|
||||
<Tooltip content="应用列表" placement="bottom">
|
||||
<Button type="ghost" icon="android-apps" @click="linkApp()"></Button>
|
||||
</Tooltip>
|
||||
<Tooltip content="退出登录" placement="bottom-end">
|
||||
<Button type="ghost" icon="power" @click="logout"></Button>
|
||||
</Tooltip>
|
||||
<!-- 如果是3.0.icon改成 -->
|
||||
<!--
|
||||
md-happy
|
||||
md-apps
|
||||
md-power
|
||||
-->
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- 标题 -->
|
||||
<div class="path-nav">
|
||||
<h1>{{ pathName }}</h1>
|
||||
</div>
|
||||
<!-- 侧边 -->
|
||||
<div class="leftmenu">
|
||||
<div class="" style="height: 100%">
|
||||
<div class="title-top">{{ appName }}</div>
|
||||
<ul class="title-box">
|
||||
<li
|
||||
v-for="(item, index) in modList"
|
||||
:key="index"
|
||||
:class="{
|
||||
active: item.page.toLowerCase() == currPath.toLowerCase(),
|
||||
}"
|
||||
>
|
||||
<!-- <router-link :to="item.page" >{{item.name}}</router-link> -->
|
||||
<a href="javascript:;" @click="flushCom(item.page)">{{ item.name }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
inject: ["reload"],
|
||||
props: {
|
||||
layoutData: {
|
||||
appName: String,
|
||||
appList: Array,
|
||||
modList: Array,
|
||||
userInfo: Object,
|
||||
ssoHost: String,
|
||||
baseHost: String,
|
||||
isAlone: Boolean, //是否只有一个选项卡
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
username: "",
|
||||
pathName: "",
|
||||
logoUrl: "",
|
||||
currPath: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
listNumber: function () {
|
||||
return this.pathList.sort(function (a, b) {
|
||||
return a.modId - b.modId;
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const _this = this;
|
||||
for (const key in _this.layoutData) _this[key] = _this.layoutData[key];
|
||||
this.username = this.userInfo.name;
|
||||
this.logoUrl = this.baseHost + "/img/logo.png";
|
||||
_this.routeChange(_this.$route); //初次加载时手动触发route的change
|
||||
this.$watch("$route", _this.routeChange);
|
||||
$(".base-wrap-main").css("padding-top", "145px");
|
||||
},
|
||||
methods: {
|
||||
logout() {
|
||||
//退出登陆
|
||||
let url = window.location.href;
|
||||
url = "/logout?service=" + url;
|
||||
top.location.href = this.ssoHost + url;
|
||||
},
|
||||
routeChange(router) {
|
||||
const _this = this;
|
||||
window.document.title = router.meta.title || "弘育云平台";
|
||||
let currentMod = router.meta.modId;
|
||||
//时间有限,仅支持一层.暂时写死,有需求再改
|
||||
_this.modList.forEach(element => {
|
||||
let childIndex = element.children.findIndex(x => x.modId == currentMod);
|
||||
if (currentMod == element.modId || childIndex > -1) {
|
||||
_this.currPath = element.page;
|
||||
_this.pathName = element.name;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
linkApp() {
|
||||
location.href = this.baseHost + "/v/home";
|
||||
},
|
||||
linkUser() {
|
||||
location.href = this.baseHost + "/v/userinfo";
|
||||
},
|
||||
flushCom(page) {
|
||||
//return;
|
||||
const path = this.$route.path;
|
||||
// console.log(page,path);
|
||||
if (page === path) {
|
||||
this.reload();
|
||||
//this.$root.$children[0].reload()
|
||||
} else {
|
||||
this.$router.push(page);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" >
|
||||
.layout_old {
|
||||
.header {
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 22;
|
||||
background-color: #fff;
|
||||
background-image: linear-gradient(143deg, #6c91f0 45%, #7863b4 81%, #7a5aa9);
|
||||
.header-logo {
|
||||
width: 200px;
|
||||
height: 100%;
|
||||
float: left;
|
||||
position: relative;
|
||||
}
|
||||
.header-logo-title {
|
||||
margin-left: 32px;
|
||||
position: relative;
|
||||
top: 20px;
|
||||
.logo-box {
|
||||
background: url(/static/image/logo.png) no-repeat;
|
||||
width: 450px;
|
||||
height: 70px;
|
||||
}
|
||||
}
|
||||
.header-aside {
|
||||
float: right;
|
||||
margin: 0 30px 0 0;
|
||||
position: relative;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
.aside-box {
|
||||
margin: 26px 0 22px 0;
|
||||
.icon-box {
|
||||
width: 34px;
|
||||
font-size: 18px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
a {
|
||||
color: #fff;
|
||||
&:hover {
|
||||
color: #2d8cf0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.aside-btn-list {
|
||||
.ivu-btn {
|
||||
padding: 0px;
|
||||
border: 0px;
|
||||
width: 35px;
|
||||
i {
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
p {
|
||||
float: left;
|
||||
color: #ffffff;
|
||||
padding-right: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.path-nav {
|
||||
position: fixed;
|
||||
z-index: 21;
|
||||
top: 70px;
|
||||
height: 54px;
|
||||
left: 200px;
|
||||
box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
|
||||
background: #fff;
|
||||
width: 100%;
|
||||
padding: 0 15px;
|
||||
box-sizing: border-box;
|
||||
min-width: 767px;
|
||||
h1 {
|
||||
float: left;
|
||||
font-size: 16px;
|
||||
color: #464c5b;
|
||||
margin: auto;
|
||||
line-height: 56px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.leftmenu {
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
-moz-overflow: auto;
|
||||
overflow: auto\9;
|
||||
overflow: overlay;
|
||||
overflow-x: hidden;
|
||||
background: #8791a5 !important;
|
||||
height: 100%;
|
||||
width: 200px;
|
||||
padding-top: 70px;
|
||||
box-sizing: border-box;
|
||||
& > div {
|
||||
overflow-y: auto;
|
||||
}
|
||||
.title-top {
|
||||
height: 54px;
|
||||
line-height: 54px;
|
||||
background: #3e485a;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
width: 200px;
|
||||
color: #ffffff;
|
||||
}
|
||||
.title-box {
|
||||
background: #eaedf2;
|
||||
width: 200px;
|
||||
overflow: overlay;
|
||||
border-right: 0px;
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
outline: 0;
|
||||
list-style: none;
|
||||
color: #495060;
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
li {
|
||||
text-align: center;
|
||||
background: #8791a5;
|
||||
padding: 0px !important;
|
||||
border-bottom: 1px solid #a5adbf;
|
||||
transition: all 200ms;
|
||||
&:hover {
|
||||
border-left: 4px solid #6c8fed;
|
||||
background: #f3f3f3;
|
||||
}
|
||||
&.active {
|
||||
background: #f3f3f3;
|
||||
a {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
a {
|
||||
color: #ffffff;
|
||||
display: block;
|
||||
padding: 16px 0px 14px 34px;
|
||||
text-align: left;
|
||||
color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: rgb(51, 51, 51);
|
||||
}
|
||||
}
|
||||
a {
|
||||
color: #495060;
|
||||
}
|
||||
}
|
||||
}
|
||||
.wrap-main {
|
||||
padding: 124px 0 0 200px;
|
||||
}
|
||||
.nav-btn-wrap {
|
||||
top: 78px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
import Vue from "vue";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
|
||||
import api from "./api/index.js";
|
||||
// 将API方法绑定到全局
|
||||
Vue.prototype.$api = api;
|
||||
|
||||
import "@babel/polyfill";
|
||||
// import "babel-polyfill";
|
||||
|
||||
// 引用工具文件
|
||||
import utils from "./utils/index.js";
|
||||
// 将工具方法绑定到全局
|
||||
Vue.prototype.$utils = utils;
|
||||
|
||||
import APIConfig from "./config/apiConf.js";
|
||||
window.APIConfig = APIConfig;
|
||||
|
||||
import "view-design/dist/styles/iview.css";
|
||||
import ViewUI from "view-design";
|
||||
Vue.use(ViewUI);
|
||||
|
||||
import conf from "./config/hostConf.js";
|
||||
Vue.prototype.$conf = conf;
|
||||
window.conf = conf;
|
||||
|
||||
import "./assets/styles/main.scss";
|
||||
|
||||
// 是否是IE内核
|
||||
//代码高亮文件引入(IE暂不支持)
|
||||
import hljs from "highlight.js";
|
||||
//样式文件,这里我选的是sublime样式,文件里面还有其他样式可供选择
|
||||
// import "highlight.js/styles/monokai-sublime.css";
|
||||
// import "highlight.js/styles/vs2015.css";
|
||||
import "highlight.js/styles/atelier-dune-light.css";
|
||||
|
||||
Vue.directive("highlight", function(el) {
|
||||
let blocks = el.querySelectorAll("pre code");
|
||||
blocks.forEach(block => {
|
||||
hljs.highlightBlock(block);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
import codeModal from "./mixins/code_modal";
|
||||
Vue.mixin(codeModal);
|
||||
|
||||
var EventBus = new Vue(); //事件总线
|
||||
Object.defineProperties(Vue.prototype, {
|
||||
$bus: {
|
||||
get: function() {
|
||||
return EventBus;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
new Vue({
|
||||
router,
|
||||
render: h => h(App)
|
||||
}).$mount("#app");
|
||||
@@ -0,0 +1,8 @@
|
||||
import codeModal from "../components/codeModal/index.js";
|
||||
export default {
|
||||
methods: {
|
||||
showCode({ name, url, type = "vue" }) {
|
||||
codeModal({ name, url, type });
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
export const self_viewport = {
|
||||
data() {
|
||||
return {
|
||||
tableHeight: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
useTableHeight() {
|
||||
return (settings = {}) => {
|
||||
let { isSearch = true, isPage = true, isTabs = false, isOperat = true, otherH = 0 } = settings;
|
||||
let bodyH = this.tableHeight,
|
||||
headerH = 112,
|
||||
searchH = 52,
|
||||
operatH = 48,
|
||||
tabsH = 56,
|
||||
pageH = 72,
|
||||
paddingH = 8;
|
||||
let tableH = bodyH - headerH - paddingH;
|
||||
isOperat && (tableH -= operatH);
|
||||
isTabs && (tableH -= tabsH);
|
||||
isSearch && (tableH -= searchH);
|
||||
isPage && (tableH -= pageH);
|
||||
otherH > 0 && (tableH -= otherH);
|
||||
return tableH;
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.tableHeight = document.body.clientHeight;
|
||||
window.onresize = () => {
|
||||
return (() => {
|
||||
this.tableHeight = document.body.clientHeight;
|
||||
})();
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
// 去掉export function,写内部方法
|
||||
export default {
|
||||
methods: {
|
||||
treeRenderContent(h, params) {
|
||||
const { root, node, data } = params;
|
||||
const icon0 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAKJJREFUOE9jZKASYKSSOQzUN+j/QaH7DAwMCmgufMDw758jo+OHB4RcDnfR/4NC/3EovsDAyPgBh9wDRru3iSA5VIOkMxgYeHQIWQ6R/3CUgeHlcgZG+3dgMxAGnVT+zyAVz8DAIUecQT8eMTA8W8jAaH4XzaDrjri8htdgRs39owYRCPqhEUbYsgihNPWAUXO/IkqCJKSDkDz1cz8hGwnJAwCJjEAToczWhwAAAABJRU5ErkJggg==';
|
||||
const iconOther = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAaVJREFUOE+t1D9v00AYx/HvpSFqqyDdgKqOqVBVIRBK3kGY6NIhqtQ1tXgBSV9B4ldAeAEoZmIB3kK8M4QljM0t7XxDhgjcXHXnP4odEoOER/vu4989z2ML/tMlypz22EhAhp5Qu9ZuhRKgh6FvIQRD4NM2cAPaAPIxFIIg9IRfTJdBJUBxn8Lgh+9EkD5wUHtsGhgmQKOsZoXnNmEr9IROIYlhBHT/CYqP6dk9uRolyWxRd4OCEPDWC++gydw0IhgLUHvg+6E74gBDO5cwBvxBG/UA74HmHrTenCRHm8yNjHA1aiYxgwS0UA/QKfDbMBQiSxxWoZNB6Vu/35nhcsVgGcV3BDjQQhH0BPQNyMMnqKc1/NdHha7ZTZefTXBxRvftKayAWw0pmL6oWkG/fIY6qNL8OoNgSkCFm2LXprb9x3W4eoXqvKBxv4jBaIV+LtFyH/lthvzyExa/HK+T9qt81z6aPsLVxIHdJpyfxnlcgh9rgOEDFUY2zUb7s+FccZ2Asl6LoSxBAchN9p+GsDBTmi1AKZQucCDo9AjbJr/0f/S3n8wj0GCqE4RTEr0AAAAASUVORK5CYII=';
|
||||
|
||||
return h('span', [
|
||||
h('img', {
|
||||
attrs: {
|
||||
src: node.nodeKey == 0 ? icon0 : iconOther
|
||||
},
|
||||
style: 'width: 16px; height: 16px;vertical-align: sub;'
|
||||
}),
|
||||
h('span', {
|
||||
style: {
|
||||
display: 'inline-block',
|
||||
cursor: "pointer",
|
||||
backgroundColor: node.node.selected ? "#e5e5e5" : ""
|
||||
},
|
||||
on: {
|
||||
click: (e) => {
|
||||
e.stopPropagation()
|
||||
this.$emit("on-tree-change", node.node);
|
||||
}
|
||||
}
|
||||
}, data.title)
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
import Vue from "vue";
|
||||
import VueRouter from "vue-router";
|
||||
|
||||
const studySystemChoice = () => import("../views/studySystemChoice.vue");
|
||||
const itemSet = () => import("../views/itemSet.vue");
|
||||
const areaOperateDaily = () => import("../views/areaOperateDaily.vue");
|
||||
const schoolSetting = () => import("../views/schoolSetting.vue");
|
||||
const subjectManForZy = () => import("../views/subjectManForZy.vue");
|
||||
const classManage = () => import("../views/classManage.vue");
|
||||
const electiveClassManage = () => import("../views/electiveClassManage.vue");
|
||||
const electiveClassManageDetail = () => import("../views/electiveClassManageDetail.vue");
|
||||
const ChristianityDetail = () => import("../views/classManage/ChristianityDetail.vue");
|
||||
const subjectSetzhi = () => import("../views/subjectSetzhi.vue");
|
||||
const teacherManage = () => import("../views/teacherManage.vue");
|
||||
const studentManage = () => import("../views/studentManage.vue");
|
||||
const historySearch = () => import("../views/historySearch.vue");
|
||||
const historySearchDetail = () => import("../views/historySearchDetail.vue");
|
||||
const studentYDManage = () => import("../views/studentYDManage.vue");
|
||||
const zhuanruinfo = () => import("../views/zhuanruinfo.vue");
|
||||
const zhuanruinfostu = () => import("../views/zhuanruinfostu.vue");
|
||||
const dailySearch = () => import("../views/dailySearch.vue");
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: "/",
|
||||
name: "studySystemChoice",
|
||||
component: studySystemChoice,
|
||||
meta: { title: "学制选择", modId: 1, icon: "icon-shezhi" }
|
||||
},
|
||||
{
|
||||
path: '/itemSet',
|
||||
name: "itemSet",
|
||||
component: itemSet,
|
||||
meta:{title:"时段设置",modId:2,icon: "icon-shezhi"}
|
||||
},
|
||||
{
|
||||
path: '/areaOperateDaily',
|
||||
name: "areaOperateDaily",
|
||||
component: areaOperateDaily,
|
||||
meta:{title:"区域操作日志",modId:3,icon: "icon-chaxun"}
|
||||
},
|
||||
{
|
||||
path: '/schoolSetting',
|
||||
name: "schoolSetting",
|
||||
component: schoolSetting,
|
||||
meta:{title:"学校设置",modId:4,icon: "icon-cshxd"}
|
||||
},
|
||||
{
|
||||
path: '/subjectManForZy',
|
||||
name: "subjectManForZy",
|
||||
component: subjectManForZy,
|
||||
meta:{title:"课程设置",modId:5,icon: "icon-xuekeshezhi"}
|
||||
},
|
||||
{
|
||||
path: '/subjectSetzhi',
|
||||
name: "subjectSetzhi",
|
||||
component: subjectSetzhi,
|
||||
meta:{title:"学科管理",modId:6,icon: "icon-xuekeshezhi"}
|
||||
},
|
||||
{
|
||||
path: '/classManage',
|
||||
name: "classManage",
|
||||
component: classManage,
|
||||
meta:{title:"班级管理",modId:7,icon: "icon-banji"}
|
||||
},
|
||||
{
|
||||
path: "/ChristianityDetail",
|
||||
name: "ChristianityDetail",
|
||||
component: ChristianityDetail,
|
||||
meta: { title: "班级管理", modId: 7,parentPath:"/classManage" }
|
||||
},
|
||||
{
|
||||
path: '/electiveClassManage',
|
||||
name: "electiveClassManage",
|
||||
component: electiveClassManage,
|
||||
meta:{title:"选修班管理",modId:8,icon: "icon-banji"}
|
||||
},
|
||||
{
|
||||
path: "/electiveClassManageDetail",
|
||||
name: "electiveClassManageDetail",
|
||||
component: electiveClassManageDetail,
|
||||
meta: { title: "选修班管理", modId: 8,parentPath:"/electiveClassManage" }
|
||||
},
|
||||
{
|
||||
path: '/teacherManage',
|
||||
name: "teacherManage",
|
||||
component: teacherManage,
|
||||
meta:{title:"教师管理",modId:9,icon: "icon-jiaoshi"}
|
||||
},
|
||||
{
|
||||
path: '/studentManage',
|
||||
name: "studentManage",
|
||||
component: studentManage,
|
||||
meta:{title:"学生管理",modId:10,icon: "icon-xuesheng"}
|
||||
},
|
||||
{
|
||||
path: '/historySearch',
|
||||
name: "historySearch",
|
||||
component: historySearch,
|
||||
meta:{title:"历史查询",modId:11,icon: "icon-chaxun"}
|
||||
},
|
||||
{
|
||||
path: "/historySearchDetail",
|
||||
name: "historySearchDetail",
|
||||
component: historySearchDetail,
|
||||
meta: { title: "历史查询", modId: 11,parentPath:"/historySearch" }
|
||||
},
|
||||
{
|
||||
path: '/studentYDManage',
|
||||
name: "studentYDManage",
|
||||
component: studentYDManage,
|
||||
meta:{title:"学生异动管理",modId:12,icon: "icon-xuesheng"}
|
||||
},
|
||||
{
|
||||
path: '/zhuanruinfo',
|
||||
name: "zhuanruinfo",
|
||||
component: zhuanruinfo,
|
||||
meta:{title:"教师转入管理",modId:13,icon: "icon-jiaoshi"}
|
||||
},
|
||||
{
|
||||
path: '/zhuanruinfostu',
|
||||
name: "zhuanruinfostu",
|
||||
component: zhuanruinfostu,
|
||||
meta:{title:"学生转入管理",modId:14,icon: "icon-xuesheng"}
|
||||
},
|
||||
{
|
||||
path: '/dailySearch',
|
||||
name: "dailySearch",
|
||||
component: dailySearch,
|
||||
meta:{title:"日志管理",modId:15,icon: "icon-chaxun"}
|
||||
},
|
||||
];
|
||||
|
||||
const router = new VueRouter({
|
||||
base: process.env.BASE_URL,
|
||||
routes
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -0,0 +1,245 @@
|
||||
export default {
|
||||
goodTime (str) {
|
||||
let now = new Date().getTime()
|
||||
let oldTime = new Date(str).getTime()
|
||||
let difference = now - oldTime
|
||||
let result = ''
|
||||
let minute = 1000 * 60
|
||||
let hour = minute * 60
|
||||
let day = hour * 24
|
||||
let month = day * 30
|
||||
let year = month * 12
|
||||
let _year = difference / year
|
||||
let _month = difference / month
|
||||
let _week = difference / (7 * day)
|
||||
let _day = difference / day
|
||||
let _hour = difference / hour
|
||||
let _min = difference / minute
|
||||
|
||||
if (_year >= 1) {
|
||||
result = '发表于 ' + ~~(_year) + ' 年前'
|
||||
} else if (_month >= 1) {
|
||||
result = '发表于 ' + ~~(_month) + ' 个月前'
|
||||
} else if (_week >= 1) {
|
||||
result = '发表于 ' + ~~(_week) + ' 周前'
|
||||
} else if (_day >= 1) {
|
||||
result = '发表于 ' + ~~(_day) + ' 天前'
|
||||
} else if (_hour >= 1) {
|
||||
result = '发表于 ' + ~~(_hour) + ' 个小时前'
|
||||
} else if (_min >= 1) {
|
||||
result = '发表于 ' + ~~(_min) + ' 分钟前'
|
||||
} else {
|
||||
result = '刚刚'
|
||||
}
|
||||
return result
|
||||
},
|
||||
/**
|
||||
* iView2 Tree 公用方法:选中指定ID节点,自动展开所有父节点
|
||||
* @param {Array} treeData 树形原始数据
|
||||
* @param {Number|String} targetId 要选中的节点id
|
||||
* @param {Object} vueThis 当前Vue组件this实例
|
||||
*/
|
||||
selectTreeNodeById(treeData, targetId, vueThis) {
|
||||
const loop = function (nodes, parentNode) {
|
||||
for (let node of nodes) {
|
||||
// 清空所有节点选中状态
|
||||
vueThis.$set(node, 'selected', false)
|
||||
|
||||
if (node.id === targetId) {
|
||||
// 目标节点设为选中
|
||||
vueThis.$set(node, 'selected', true)
|
||||
let p = parentNode
|
||||
// 逐层向上展开父节点
|
||||
while (p) {
|
||||
vueThis.$set(p, 'expand', true)
|
||||
p = p._parent
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if (node.children && node.children.length) {
|
||||
// 绑定父节点引用
|
||||
node.children.forEach(child => child._parent = node)
|
||||
const res = loop(node.children, node)
|
||||
if (res) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
loop(treeData, null)
|
||||
},
|
||||
strToHexCharCode(_str) {
|
||||
if (_str === "") return "";
|
||||
var hexCharCode = [];
|
||||
for (var i = 0; i < _str.length; i++) {
|
||||
var str = _str.charCodeAt(i).toString(16);
|
||||
if (_str.length == 1) str += "0" + _str;
|
||||
hexCharCode.push(str);
|
||||
}
|
||||
return hexCharCode.join("");
|
||||
},
|
||||
dateFormat(_date,fmt){
|
||||
var date=new Date(_date);
|
||||
var o = {
|
||||
"M+": date.getMonth() + 1, //月份
|
||||
"d+": date.getDate(), //日
|
||||
"H+": date.getHours(), //小时
|
||||
"m+": date.getMinutes(), //分
|
||||
"s+": date.getSeconds(), //秒
|
||||
"q+": Math.floor((date.getMonth() + 3) / 3), //季度
|
||||
"S": date.getMilliseconds() //毫秒
|
||||
};
|
||||
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
|
||||
for (var k in o)
|
||||
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
|
||||
return fmt;
|
||||
},
|
||||
dataFilter(_key,arry) {
|
||||
for (var key in arry) {
|
||||
if (arry.hasOwnProperty(key)) {
|
||||
var element = arry[key];
|
||||
if(element.k==_key)
|
||||
return element.v;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
},
|
||||
myUpload(url,fileObj,data,callback){
|
||||
var FileController ="/api"+ url; // 接收上传文件的后台地址
|
||||
if (!fileObj ||fileObj.length==0) {
|
||||
console.error('请选择上传文件'); return;
|
||||
}
|
||||
// FormData 对象
|
||||
var form = new FormData();
|
||||
//表单数据
|
||||
for (let key in data) {
|
||||
const element = data[key];
|
||||
form.append(key,element);
|
||||
}
|
||||
form.append("file", fileObj);// 文件对象
|
||||
// XMLHttpRequest 对象
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("post", FileController, true);
|
||||
xhr.onload = function (resp) {
|
||||
var obj = JSON.parse(resp.currentTarget.response);
|
||||
if(callback)
|
||||
callback(obj);
|
||||
};
|
||||
xhr.send(form);
|
||||
},
|
||||
comSetting(){//公共插件基础配置,如有需要,覆盖即可
|
||||
const tree={
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showIcon: false,
|
||||
},
|
||||
check: {
|
||||
enable: false,
|
||||
},
|
||||
callback:{}
|
||||
}
|
||||
return {
|
||||
tree:tree,
|
||||
}
|
||||
},
|
||||
comSetting1(){//公共插件基础配置,如有需要,覆盖即可
|
||||
const tree={
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showIcon: false,
|
||||
},
|
||||
edit: {
|
||||
enable: true,
|
||||
showRemoveBtn: false,
|
||||
showRenameBtn: false,
|
||||
drag: { prev: true, next: true,inner: false}
|
||||
},
|
||||
check: {
|
||||
enable: false
|
||||
},
|
||||
data: {
|
||||
simpleData: {
|
||||
enable: true
|
||||
}
|
||||
},
|
||||
callback: {
|
||||
|
||||
}
|
||||
}
|
||||
return {
|
||||
tree:tree,
|
||||
}
|
||||
},
|
||||
|
||||
openFistNode(_zNodes){//展开一级节点
|
||||
if(_zNodes&&_zNodes.length>0){
|
||||
for (var key in _zNodes) {
|
||||
if (_zNodes.hasOwnProperty(key)) {
|
||||
var element = _zNodes[key];
|
||||
element.open=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
_zNodes.open=true;
|
||||
}
|
||||
return _zNodes;
|
||||
},
|
||||
editorFormat(val){//富文本提取文字
|
||||
return val.replace(/<[^>]+>/g, "");
|
||||
},
|
||||
mathFormat(val,number=2){//小数点截取,默认取2位
|
||||
if(isNaN(val))return 0;
|
||||
var num=Math.pow(10,number);
|
||||
return Math.floor(val*num)/num;
|
||||
},
|
||||
fileSize(size){//返回文件大小
|
||||
if(!size) return '';
|
||||
if(size/1024<1024){
|
||||
size=Math.ceil(size/1024);
|
||||
return size+'KB';
|
||||
}else if(size/(1024*1024)<1024){
|
||||
size=Math.ceil(size/(1024*1024)*100)/100;
|
||||
return size+'MB';
|
||||
}else if(size/(1024*1024*1024)<1024){
|
||||
size=Math.ceil(size/(1024*1024*1024)*100)/100;
|
||||
return size+'GB';
|
||||
}
|
||||
},
|
||||
handleValidate(_this,name){//表单验证
|
||||
let isValid = false;
|
||||
_this.$refs[name].validate(function (valid) {
|
||||
if (valid) {
|
||||
isValid = true;
|
||||
} else {
|
||||
// _this.$Message.info('表单验证失败!');
|
||||
|
||||
_this.$Message.info('请填写红色星号内容!');
|
||||
}
|
||||
})
|
||||
return isValid;
|
||||
},
|
||||
handleReset(_this,resetName,name) {//表单重置
|
||||
if(name&&_this.isModal&&_this.isModal[name]) _this.isModal[name] = false;
|
||||
if (resetName) {
|
||||
_this.$refs[resetName].resetFields();
|
||||
}
|
||||
},
|
||||
downFile(id) {//下载文件
|
||||
location.href = APIConfig.Base.FileDown + '?id=' + id;
|
||||
},
|
||||
|
||||
localStorage:{
|
||||
get(key){
|
||||
return localStorage.getItem(key);
|
||||
},
|
||||
set(key,val){
|
||||
localStorage.setItem(key,val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<!-- 外层全屏容器,用于高度自适应 -->
|
||||
<div class="page-wrap">
|
||||
<!-- 顶部搜索栏 -->
|
||||
<div class="search-wrap">
|
||||
<div class="search-right">
|
||||
<Input
|
||||
v-model="keyword"
|
||||
placeholder="请输入用户名、IP、模块或详细操作"
|
||||
search
|
||||
style="width:460px"
|
||||
@on-search="searchData"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格自适应滚动容器(核心滚动区域) -->
|
||||
<div class="table-scroll-wrap">
|
||||
<Table
|
||||
border
|
||||
stripe
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
class="log-table"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 底部分页:固定在容器底部,不会随表格滚动 -->
|
||||
<div class="pagination-wrap">
|
||||
<span class="total-text">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:page-size-opts="[10, 20, 50, 100]"
|
||||
show-sizer
|
||||
@on-change="handlePageChange"
|
||||
@on-page-size-change="handleSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'OperateLog',
|
||||
data() {
|
||||
return {
|
||||
keyword: '',
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
|
||||
tableColumns: [
|
||||
{ title: '序号', type: 'index', align: 'center', width: 70 },
|
||||
{ title: '用户', key: 'operator', align: 'center', width: 130 },
|
||||
{ title: 'IP', key: 'ip', align: 'center', width: 150 },
|
||||
{ title: '模块', key: 'module', align: 'center', width: 160 },
|
||||
{ title: '详细操作', key: 'content', align: 'left' },
|
||||
{
|
||||
title: '时间',
|
||||
key: 'operateTime',
|
||||
align: 'center',
|
||||
width: 190,
|
||||
render: (h, params) => {
|
||||
return h("div", { style: "line-height: 56px" }, this.$utils.dateFormat(params.row.operateTime,'yyyy-MM-dd HH:mm:ss'));
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadLogData();
|
||||
},
|
||||
methods: {
|
||||
// 请求日志列表
|
||||
loadLogData() {
|
||||
const _this = this;
|
||||
var item = {
|
||||
keyword:_this.keyword,
|
||||
page:_this.pageNum-1,
|
||||
size:_this.pageSize
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.systemSearch, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.tableData = resp.data.content;
|
||||
_this.total=resp.data.total;
|
||||
} else {
|
||||
_this.tableData = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
searchData() {
|
||||
this.pageNum = 1
|
||||
this.loadLogData()
|
||||
},
|
||||
handlePageChange(page) {
|
||||
this.pageNum = page
|
||||
this.loadLogData()
|
||||
},
|
||||
handleSizeChange(size) {
|
||||
this.pageSize = size
|
||||
this.pageNum = 1
|
||||
this.loadLogData()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 页面撑满父容器高度,必须设置父级html、body高度100% */
|
||||
.page-wrap {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.search-wrap {
|
||||
flex-shrink: 0; /* 固定高度,不压缩 */
|
||||
background: #f7f7f7;
|
||||
margin-bottom: 16px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.search-right {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 表格容器:自动填充剩余高度,内容超出滚动 */
|
||||
.table-scroll-wrap {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.log-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 分页区域:固定在底部,不参与滚动 */
|
||||
.pagination-wrap {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.total-text {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div style="height:100%;">
|
||||
<Christianity v-if="type==1"></Christianity>
|
||||
<HigherEducation v-if="type==2"></HigherEducation>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Christianity from "./classManage/Christianity";
|
||||
import HigherEducation from "./classManage/HigherEducation";
|
||||
export default {
|
||||
name: 'ClassManage',
|
||||
components: { Christianity,HigherEducation },
|
||||
data() {
|
||||
return {
|
||||
type:0,
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.getType();
|
||||
},
|
||||
methods: {
|
||||
//获取学制
|
||||
getType:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getType, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.type = resp.data;
|
||||
}else{
|
||||
_this.type=1;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,786 @@
|
||||
<template>
|
||||
<div class="container-full-height">
|
||||
<div class="layout-flex-row">
|
||||
<!-- 左侧树形容器 高度撑满、内部滚动 -->
|
||||
<div class="tree-wrap">
|
||||
<my-tree :treeData="treeData" :selectId="selectnodeid" @on-tree-click="treeLink"></my-tree>
|
||||
</div>
|
||||
|
||||
<!-- 右侧整体容器 高度撑满 -->
|
||||
<div class="right-full-wrap">
|
||||
<!-- 顶部按钮栏 固定高度不滚动 -->
|
||||
<div class="top-btn-bar">
|
||||
<Dropdown trigger="click" @on-click="changefieid">
|
||||
<Button type="primary">
|
||||
添加班级
|
||||
<Icon type="ios-arrow-down"></Icon>
|
||||
</Button>
|
||||
<DropdownMenu slot="list">
|
||||
<DropdownItem name="openAddSingleClass">添加单个班级</DropdownItem>
|
||||
<DropdownItem name="openMultiNumModal">添加多个班级</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
<Button type="success" style="margin-left:10px" @click="openImportModal">班级信息导入</Button>
|
||||
</div>
|
||||
|
||||
<!-- 表格容器:填充剩余高度,纵向滚动 -->
|
||||
<div class="table-auto-scroll">
|
||||
<Table
|
||||
border
|
||||
stripe
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
></Table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗1:添加多个班级 设置数量 -->
|
||||
<Modal v-model="multiClassModal" title="设置添加班级数量" width="400">
|
||||
<div style="padding:16px 8px;">
|
||||
<div style="display:flex;align-items:center;">
|
||||
<span style="width:80px;">班级数</span>
|
||||
<Input v-model.number="addClassCount" type="number" min="1" />
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="multiClassModal = false">取消</Button>
|
||||
<Button type="primary" @click="submitBatchAdd">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗2:班级信息导入 -->
|
||||
<Modal v-model="importModal" title="班级信息导入" width="560">
|
||||
<!-- <div style="padding:18px 10px;display:flex;align-items:center;gap:20px;">
|
||||
<Upload action="" :before-upload="beforeUpload">
|
||||
<Button>选择要上传的文件</Button>
|
||||
</Upload>
|
||||
<a href="javascript:;" style="color:#2d7ff9" @click="downloadTemplate">点击链接下载[用户导入模板.xls]</a>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="importModal = false">取消</Button>
|
||||
<Button type="primary" @click="confirmImport">确定</Button>
|
||||
</div> -->
|
||||
<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>
|
||||
|
||||
<!-- 弹窗3:选择教师 -->
|
||||
<Modal v-model="selectTeacherModal" title="选择教师" width="420">
|
||||
<div style="padding:10px 5px;">
|
||||
<div style="margin-bottom:16px;display:flex;align-items:center;">
|
||||
<span style="width:75px;">科室</span>
|
||||
<Select v-model="deptFilter" placeholder="按科室过滤" style="flex:1" @on-change="getteacherSelect" clearable>
|
||||
<Option v-for="item in groupteacherSelectlist" :key="item.id" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;">
|
||||
<span style="width:75px;">教师</span>
|
||||
<Select v-model="selectedTeacher" style="flex:1" 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="selectTeacherModal = false">取消</Button>
|
||||
<Button type="primary" @click="confirmSelectTeacher">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗5:选择校区 -->
|
||||
<Modal v-model="selectCampusModal" title="选择校区" width="420">
|
||||
<div style="padding:10px 5px;">
|
||||
<div style="display:flex;align-items:center;">
|
||||
<span style="width:75px;">校区</span>
|
||||
<Select v-model="selectedCampus" style="flex:1" placeholder="请选择">
|
||||
<Option v-for="item in campusselectlist" :key="item.id" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="selectCampusModal = false">取消</Button>
|
||||
<Button type="primary" @click="confirmSelectCampus">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myTree from "../../components/my_tree";
|
||||
export default {
|
||||
components: { myTree},
|
||||
name: 'ClassHeightFullPage',
|
||||
data() {
|
||||
return {
|
||||
schsystemId:'',
|
||||
selectnodeid:'',
|
||||
treeData: [],
|
||||
selectedTreeNode: null,
|
||||
selectGrade: '预备',
|
||||
|
||||
multiClassModal: false,
|
||||
addClassCount: 2,
|
||||
importModal: false,
|
||||
spinShow:false,
|
||||
selectTeacherModal: false,
|
||||
editRowIndex: null,
|
||||
editField: '',
|
||||
deptFilter: '',
|
||||
selectedTeacher: '',
|
||||
|
||||
selectCampusModal: false,
|
||||
campusEditIndex: null,
|
||||
selectedCampus: '',
|
||||
|
||||
tableColumns: [],
|
||||
tableData: [],
|
||||
campusselectlist:[],
|
||||
groupteacherSelectlist:[],
|
||||
teacherSelectlist:[],
|
||||
UpParmas:{
|
||||
fileName:'',
|
||||
listData:{},
|
||||
datapre:{},
|
||||
actionUrl:APIConfig.BschClassSystem.schclassImport,
|
||||
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.getGradeTree();
|
||||
this.getgroupteacherSelect();
|
||||
this.getteacherSelect();
|
||||
this.getcampusselect();
|
||||
this.initTableColumn();
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
//获取年级树
|
||||
getGradeTree:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getGradeTree, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.treeData = resp.data;
|
||||
if(resp.data.children.length>0){
|
||||
// 起始节点为 data
|
||||
const pathArr = _this.getFirstPath(resp.data);
|
||||
_this.selectnodeid=pathArr[pathArr.length-1].id;
|
||||
_this.schsystemId=pathArr[pathArr.length-1].schsystemId;
|
||||
_this.getsearcBaseSchClass();
|
||||
}
|
||||
}else{
|
||||
_this.treeData=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取最后一级的map
|
||||
getFirstPath(rootNode) {
|
||||
const path = [];
|
||||
let cur = rootNode;
|
||||
while (cur) {
|
||||
// 存入当前层级关键信息
|
||||
path.push({
|
||||
id: cur.id,
|
||||
name: cur.name,
|
||||
type: cur.type,
|
||||
schsystemId:cur.schsystemId,
|
||||
gradeId:cur.gradeId,
|
||||
classId:cur.classId,
|
||||
});
|
||||
// 有子节点就取第一个,没有就终止
|
||||
if (cur.children && cur.children.length > 0) {
|
||||
cur = cur.children[0];
|
||||
} else {
|
||||
cur = null;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
},
|
||||
//获取班级列表
|
||||
getsearcBaseSchClass:function(){
|
||||
const _this = this;
|
||||
var item={
|
||||
schsystemId:this.schsystemId,
|
||||
gradeId:this.selectnodeid
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getsearcBaseSchClass, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.tableData = resp.data;
|
||||
}else{
|
||||
_this.tableData=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
//教师组下拉
|
||||
getgroupteacherSelect:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getgroupteacherSelect, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.groupteacherSelectlist= resp.data;
|
||||
}else{
|
||||
_this.groupteacherSelectlist=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
//教师下拉
|
||||
getteacherSelect:function(){
|
||||
const _this = this;
|
||||
var item={
|
||||
groupId:_this.deptFilter
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getteacherSelect, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.teacherSelectlist= resp.data;
|
||||
}else{
|
||||
_this.teacherSelectlist=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
//校区下拉
|
||||
getcampusselect:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getcampusselect, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.campusselectlist= resp.data;
|
||||
}else{
|
||||
_this.campusselectlist=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
//节点点击事件
|
||||
treeLink(treeNode){
|
||||
this.schsystemId=treeNode.schsystemId;
|
||||
this.selectnodeid=treeNode.id;
|
||||
this.getsearcBaseSchClass();
|
||||
},
|
||||
initTableColumn() {
|
||||
this.tableColumns = [
|
||||
{ title: '序号', type: 'index', align: 'center', width: 70 },
|
||||
{ title: '班级名称', key: 'name', align: 'center', width: 100 },
|
||||
{
|
||||
title: '班级别名',
|
||||
align: 'center',
|
||||
render: (h, params) => {
|
||||
return h('Input', {
|
||||
props: { value: params.row.cname },
|
||||
style: { width: '150px' },
|
||||
on: {
|
||||
input: (val) => {
|
||||
this.$set(params.row, 'classAlias', val)
|
||||
this.cellChange(params.index, 'classAlias', val)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '班主任',
|
||||
align: 'center',
|
||||
width: 160,
|
||||
render: (h, params) => {
|
||||
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.openTeacherSelect(params.index, 'headTeacher')
|
||||
}
|
||||
}, [
|
||||
h('span', {
|
||||
style: {
|
||||
flex: 1,
|
||||
textAlign: 'center',
|
||||
fontSize: '14px',
|
||||
paddingLeft: '6px',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap'
|
||||
}
|
||||
}, params.row.firstTeacherName || ''),
|
||||
params.row.firstTeacherName ? h('span', {
|
||||
style: {
|
||||
width: '22px',
|
||||
height: '22px',
|
||||
lineHeight: '22px',
|
||||
textAlign: 'center',
|
||||
color: 'red',
|
||||
borderLeft: '1px solid #eee',
|
||||
flexShrink: 0,
|
||||
fontSize: '14px'
|
||||
},
|
||||
on: {
|
||||
click: (e) => {
|
||||
e.stopPropagation()
|
||||
var item={
|
||||
id:params.row.id,
|
||||
firstTeacherId:null
|
||||
};
|
||||
let url=APIConfig.BschClassSystem.editClassFirstTeacher;
|
||||
this.$api.post(url, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.$Message.success(`设置教师成功`);
|
||||
this.getsearcBaseSchClass();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, '×') : null
|
||||
])
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '副班主任',
|
||||
align: 'center',
|
||||
width: 160,
|
||||
render: (h, params) => {
|
||||
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.openTeacherSelect(params.index, 'secondTeacherName')
|
||||
}
|
||||
}, [
|
||||
h('span', {
|
||||
style: {
|
||||
flex: 1,
|
||||
textAlign: 'center',
|
||||
fontSize: '14px',
|
||||
paddingLeft: '6px',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap'
|
||||
}
|
||||
}, params.row.secondTeacherName || ''),
|
||||
params.row.secondTeacherName ? h('span', {
|
||||
style: {
|
||||
width: '22px',
|
||||
height: '22px',
|
||||
lineHeight: '22px',
|
||||
textAlign: 'center',
|
||||
color: 'red',
|
||||
borderLeft: '1px solid #eee',
|
||||
flexShrink: 0,
|
||||
fontSize: '14px'
|
||||
},
|
||||
on: {
|
||||
click: (e) => {
|
||||
e.stopPropagation()
|
||||
var item={
|
||||
id:params.row.id,
|
||||
secondTeacherId:null
|
||||
};
|
||||
let url=APIConfig.BschClassSystem.editClassSecondTeacher;
|
||||
this.$api.post(url, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.$Message.success(`设置教师成功`);
|
||||
this.getsearcBaseSchClass();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, '×') : null
|
||||
])
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '校区',
|
||||
align: 'center',
|
||||
width: 160,
|
||||
render: (h, params) => {
|
||||
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.openCampusSelect(params.index)
|
||||
}
|
||||
}, [
|
||||
h('span', {
|
||||
style: {
|
||||
flex: 1,
|
||||
textAlign: 'center',
|
||||
fontSize: '14px',
|
||||
paddingLeft: '6px',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap'
|
||||
}
|
||||
}, params.row.campusName || ''),
|
||||
params.row.campusName ? h('span', {
|
||||
style: {
|
||||
width: '22px',
|
||||
height: '22px',
|
||||
lineHeight: '22px',
|
||||
textAlign: 'center',
|
||||
color: 'red',
|
||||
borderLeft: '1px solid #eee',
|
||||
flexShrink: 0,
|
||||
fontSize: '14px'
|
||||
},
|
||||
on: {
|
||||
click: (e) => {
|
||||
e.stopPropagation()
|
||||
var item={
|
||||
id:params.row.id,
|
||||
campusId:null
|
||||
};
|
||||
let url=APIConfig.BschClassSystem.editClassCampus;
|
||||
this.$api.post(url, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.$Message.success(`校区设置成功`);
|
||||
this.getsearcBaseSchClass();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, '×') : null
|
||||
])
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
render: (h, params) => {
|
||||
return h('div', { style: { display: 'flex', gap: '8px', justifyContent: 'center' } }, [
|
||||
h('Button', {
|
||||
props: { icon: 'ios-eye-outline', type: 'text', size: 'large' },
|
||||
on: { click: () => this.viewDetail(params.row) }
|
||||
}),
|
||||
h('Button', {
|
||||
props: { icon: 'ios-trash-outline', type: 'text', color: 'red', size: 'large',disabled:params.row.disableDel },
|
||||
on: { click: () => this.deleteRow(params.index, params.row) }
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
loadTableData() {
|
||||
console.log('当前筛选年级:', this.selectGrade)
|
||||
// 替换后端请求
|
||||
},
|
||||
cellChange(rowIndex, field, value) {
|
||||
var item={
|
||||
id:this.tableData[rowIndex].id,
|
||||
cname:value
|
||||
};
|
||||
this.$api.post(APIConfig.BschClassSystem.editClassName, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
// this.$Message.success(`设置班级名称成功`);
|
||||
this.getsearcBaseSchClass();
|
||||
}
|
||||
});
|
||||
},
|
||||
//自定义类型添加
|
||||
changefieid:function(name){
|
||||
var _this=this;
|
||||
if(name=="openAddSingleClass")
|
||||
{
|
||||
var item={
|
||||
gradeId:_this.selectnodeid,
|
||||
number:1
|
||||
};
|
||||
_this.$api.post(APIConfig.BschClassSystem.addBaseSchClass, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.$Message.success(`新增1个班级!`);
|
||||
this.getsearcBaseSchClass();
|
||||
}
|
||||
});
|
||||
}else if(name=="openMultiNumModal")
|
||||
{
|
||||
this.addClassCount = 2
|
||||
this.multiClassModal = true
|
||||
}
|
||||
},
|
||||
//批量增加班级
|
||||
submitBatchAdd() {
|
||||
if (this.addClassCount < 1) return this.$Message.warning('班级数量不能小于1');
|
||||
var item={
|
||||
gradeId:this.selectnodeid,
|
||||
number:this.addClassCount
|
||||
};
|
||||
this.$api.post(APIConfig.BschClassSystem.addBaseSchClass, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.$Message.success(`批量新增${this.addClassCount}个班级`);
|
||||
this.getsearcBaseSchClass();
|
||||
this.multiClassModal = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
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.schclassdownloadTemplate+'?schId='+schId;
|
||||
window.location.href=url;
|
||||
}else{
|
||||
this.$Message.info('获取不了学校!');
|
||||
}
|
||||
},
|
||||
//附件上传模态框关闭事件
|
||||
UpfileModalcloseclick:function(){
|
||||
this.importModal=false;
|
||||
this.UpParmas={
|
||||
fileName:'',
|
||||
listData:{},
|
||||
datapre:{},
|
||||
}
|
||||
},
|
||||
|
||||
openTeacherSelect(index, field) {
|
||||
this.editRowIndex = index
|
||||
this.editField = field
|
||||
this.deptFilter = ''
|
||||
this.selectedTeacher =field=='headTeacher'? this.tableData[index].firstTeacherId:this.tableData[index].secondTeacherId;
|
||||
this.selectTeacherModal = true
|
||||
},
|
||||
confirmSelectTeacher() {
|
||||
if (!this.selectedTeacher) return this.$Message.warning('请选择教师');
|
||||
var item={
|
||||
id:this.tableData[this.editRowIndex].id
|
||||
};
|
||||
if(this.editField=='headTeacher'){
|
||||
item.firstTeacherId=this.selectedTeacher;
|
||||
}else{
|
||||
item.secondTeacherId=this.selectedTeacher;
|
||||
}
|
||||
let url=this.editField=='headTeacher'?APIConfig.BschClassSystem.editClassFirstTeacher:APIConfig.BschClassSystem.editClassSecondTeacher;
|
||||
this.$api.post(url, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.$Message.success(`设置教师成功`);
|
||||
this.getsearcBaseSchClass();
|
||||
this.selectTeacherModal = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
openCampusSelect(index) {
|
||||
this.campusEditIndex = index
|
||||
this.selectedCampus = this.tableData[index].campusId;
|
||||
this.selectCampusModal = true
|
||||
},
|
||||
confirmSelectCampus() {
|
||||
var item={
|
||||
id:this.tableData[this.campusEditIndex].id,
|
||||
campusId:this.selectedCampus
|
||||
};
|
||||
let url=APIConfig.BschClassSystem.editClassCampus;
|
||||
this.$api.post(url, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.$Message.success(`校区设置成功`);
|
||||
this.getsearcBaseSchClass();
|
||||
this.selectCampusModal = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
viewDetail(row) {
|
||||
this.$router.push('/ChristianityDetail?gradeId='+row.gradeId+'&classId='+row.classId+'&gradeclassName='+row.gradeName+row.name);
|
||||
},
|
||||
deleteRow(index, row) {
|
||||
this.$Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: `确定删除班级「${row.name}」吗?`,
|
||||
onOk: () => {
|
||||
var url=APIConfig.BschClassSystem.deleteBaseSchClass+this.tableData[index].id;
|
||||
this.$api.post(url,{},(resp)=>{
|
||||
this.$Message.success('删除成功!');
|
||||
this.getsearcBaseSchClass();
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 根容器占满父高度 */
|
||||
.container-full-height {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.layout-flex-row {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
gap: 16px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* 左侧树形 压到底部、内部滚动 */
|
||||
.tree-wrap {
|
||||
width: 220px;
|
||||
border: 1px solid #e8e8e8;
|
||||
padding: 8px;
|
||||
overflow-y: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 右侧整体容器 高度填充 */
|
||||
.right-full-wrap {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* 顶部按钮栏 固定不滚动 */
|
||||
.top-btn-bar {
|
||||
padding-bottom: 14px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 表格区域:自动填充剩余高度,纵向滚动 */
|
||||
.table-auto-scroll {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
min-height: 0;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.ivu-alert-desc{
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,363 @@
|
||||
<template>
|
||||
<div class="outer-wrap">
|
||||
<!-- 顶部栏:Tab + 班级名称 + 返回 -->
|
||||
<div class="header-bar">
|
||||
<Tabs v-model="activeTab" type="line">
|
||||
<TabPane label="任教信息" name="teacher"></TabPane>
|
||||
<TabPane label="学生列表" name="student"></TabPane>
|
||||
</Tabs>
|
||||
<div class="class-title-box">
|
||||
<span class="class-name">{{ $route.query.gradeclassName }}</span>
|
||||
<Button text @click="backPage">
|
||||
<Icon type="ios-arrow-back"></Icon>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任教信息页面 -->
|
||||
<div v-if="activeTab === 'teacher'" class="teacher-wrap">
|
||||
<div class="subject-container">
|
||||
<div
|
||||
v-for="(item, idx) in subjectList"
|
||||
:key="idx"
|
||||
class="subject-card"
|
||||
@click="openSetTeacher(idx)"
|
||||
>
|
||||
<div class="subject-name">{{ item.subName }}</div>
|
||||
<div class="teacher-name-wrap">
|
||||
<span class="teacher-name">{{ item.teacherName || '点击设置老师' }}</span>
|
||||
<span
|
||||
v-if="item.teacherId"
|
||||
class="close-btn"
|
||||
@click.stop="clearTeacher(idx)"
|
||||
>×</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 学生列表页面 -->
|
||||
<div v-if="activeTab === 'student'" class="student-wrap">
|
||||
<div class="table-scroll-box">
|
||||
<Table
|
||||
border
|
||||
stripe
|
||||
:columns="studentColumns"
|
||||
:data="studentData"
|
||||
:height="useTableHeight()+82"
|
||||
class="student-table"
|
||||
></Table>
|
||||
</div>
|
||||
<!-- <div class="pagination-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>
|
||||
|
||||
<!-- 设置教师弹窗 -->
|
||||
<Modal v-model="modalVisible" title="选择教师" width="400">
|
||||
<Form ref="form" :model="formData" :rules="formRules" label-width="90">
|
||||
<FormItem label="科室">
|
||||
<Select v-model="formData.dept" placeholder="按科室过滤" style="width:100%" @on-change="getteacherSelect" clearable transfer>
|
||||
<Option v-for="d in groupteacherSelectlist" :key="d.id" :value="d.id">{{ d.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="教师">
|
||||
<Select v-model="formData.teacher" placeholder="请选择" style="width:100%" filterable transfer>
|
||||
<Option v-for="t in teacherSelectlist" :key="t.id" :value="t.id">{{ t.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="modalVisible = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitSelectTeacher">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: 'ChristianityDetail',
|
||||
data() {
|
||||
return {
|
||||
activeTab: 'teacher',
|
||||
// 当前编辑科目下标
|
||||
currentEditIndex: null,
|
||||
|
||||
// 科目列表
|
||||
subjectList: [],
|
||||
|
||||
// 科室、教师数据源
|
||||
groupteacherSelectlist: [],
|
||||
teacherSelectlist: [],
|
||||
|
||||
modalVisible: false,
|
||||
formData: { dept: '', teacher: '' },
|
||||
formRules: {
|
||||
dept: [{ required: true, message: '请选择科室', trigger: 'change' }],
|
||||
teacher: [{ required: true, message: '请选择教师', trigger: 'change' }]
|
||||
},
|
||||
|
||||
// 学生列表分页
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
studentColumns: [
|
||||
{ title: '序号', type: 'index', align: 'center', width: 70 },
|
||||
{ title: '姓名', key: 'name', 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: 'gradeName', align: 'center' },
|
||||
{ title: '班级', key: 'className', align: 'center' },
|
||||
{ title: '身份证', key: 'idCard', align: 'center' }
|
||||
],
|
||||
studentData: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 切换标签页重新初始化拖拽
|
||||
activeTab(val) {
|
||||
if (val === 'teacher') {
|
||||
this.getSchClassTeach();
|
||||
} else{
|
||||
this.searchSchClassStudent();
|
||||
}
|
||||
}
|
||||
},
|
||||
mixins: [self_viewport],
|
||||
created(){
|
||||
this.getSchClassTeach();
|
||||
this.getgroupteacherSelect();
|
||||
this.getteacherSelect();
|
||||
},
|
||||
methods: {
|
||||
// 返回上一页
|
||||
backPage() {
|
||||
this.$router.back()
|
||||
},
|
||||
//通过班级ID获取任教
|
||||
getSchClassTeach(){
|
||||
const _this = this;
|
||||
var item={
|
||||
gradeId:_this.$route.query.gradeId,
|
||||
classId:_this.$route.query.classId
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getSchClassTeach, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.subjectList = resp.data;
|
||||
}else{
|
||||
_this.subjectList=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
//通过班级ID获取学生
|
||||
searchSchClassStudent(){
|
||||
const _this = this;
|
||||
var item={
|
||||
gradeId:_this.$route.query.gradeId,
|
||||
classId:_this.$route.query.classId
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.searchSchClassStudent, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.studentData = resp.data;
|
||||
}else{
|
||||
_this.studentData=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
// 教师组下拉
|
||||
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 = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
// 打开设置教师弹窗
|
||||
openSetTeacher(index) {
|
||||
this.currentEditIndex = index
|
||||
this.modalVisible = true
|
||||
this.formData = { dept: '', teacher:this.subjectList[index].teacherId?this.subjectList[index].teacherId:'' }
|
||||
},
|
||||
|
||||
// 移除当前科目教师
|
||||
clearTeacher(index) {
|
||||
this.$Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定移除该任课教师?',
|
||||
onOk: () => {
|
||||
this.$api.post(APIConfig.BschClassSystem.teachsdelete+this.subjectList[index].id, {}, res => {
|
||||
if (res.code === 0) {
|
||||
this.$Message.success('移除教师成功');
|
||||
this.getSchClassTeach();
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
// 弹窗提交分配教师
|
||||
submitSelectTeacher() {
|
||||
if (!this.formData.teacher) {
|
||||
this.$Message.warning('请选择教师');
|
||||
return;
|
||||
}
|
||||
const row = this.subjectList[this.currentEditIndex];
|
||||
const params = {
|
||||
id: row.id,
|
||||
gradeId:this.$route.query.gradeId,
|
||||
classId:this.$route.query.classId,
|
||||
subId: row.subId,
|
||||
teaId: this.formData.teacher
|
||||
};
|
||||
this.$api.post(APIConfig.BschClassSystem.teachssave, JSON.stringify(params), res => {
|
||||
if (res.code === 0) {
|
||||
this.$Message.success('分配教师成功');
|
||||
this.modalVisible = false;
|
||||
this.getSchClassTeach();
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.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;
|
||||
}
|
||||
|
||||
.header-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.class-title-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.class-name {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 任教信息卡片布局 */
|
||||
.teacher-wrap {
|
||||
flex: 1;
|
||||
}
|
||||
.subject-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
row-gap: 16px;
|
||||
}
|
||||
.subject-card {
|
||||
width: 180px;
|
||||
border: 1px solid #cad6f0;
|
||||
border-radius: 4px;
|
||||
padding: 12px 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.subject-name {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.teacher-name-wrap {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.teacher-name {
|
||||
font-size: 14px;
|
||||
color: #4080ff;
|
||||
}
|
||||
.close-btn {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
text-align: center;
|
||||
border-radius: 50%;
|
||||
background: #eee;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 学生列表布局 */
|
||||
.student-wrap {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-box {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.student-table {
|
||||
width: 100%;
|
||||
}
|
||||
.pagination-bottom {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.total-text {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,663 @@
|
||||
<template>
|
||||
<div class="outer-wrap">
|
||||
<div class="page-container">
|
||||
<!-- 左侧年级树形 -->
|
||||
<div class="tree-left">
|
||||
<my-tree :treeData="treeData" :selectId="selectnodeid" @on-tree-click="treeLink"></my-tree>
|
||||
</div>
|
||||
|
||||
<!-- 右侧主体区域 -->
|
||||
<div class="right-main">
|
||||
<!-- 顶部操作筛选栏 -->
|
||||
<div class="top-bar">
|
||||
<div class="btn-group">
|
||||
<Button type="primary" @click="openAddModal">添加班级</Button>
|
||||
<Button type="success" @click="handleImport">导入班级</Button>
|
||||
</div>
|
||||
<div class="filter-group">
|
||||
<Select v-model="filterCampus" placeholder="选择所属校区" style="width:150px;margin-right:10px" @on-change="searchList" clearable>
|
||||
<Option v-for="item in campusselectlist" :key="item.id" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
<Select v-model="filterDept" placeholder="选择所属系部" style="width:150px;margin-right:10px" @on-change="searchList" clearable>
|
||||
<Option v-for="item in divisionselectlist" :key="item.id" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
<Select v-model="filterMajor" placeholder="选择所属专业" style="width:150px;margin-right:10px" @on-change="searchList" clearable filterable>
|
||||
<Option v-for="item in majorsselectlist" :key="item.id" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
<Input
|
||||
v-model="keyword"
|
||||
placeholder="输入代码或名称搜索"
|
||||
style="width:200px"
|
||||
@keyup.enter="searchList"
|
||||
>
|
||||
<Icon slot="suffix" type="ios-search"></Icon>
|
||||
</Input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自适应表格容器 -->
|
||||
<div class="table-adapt-wrap">
|
||||
<div class="table-scroll-box">
|
||||
<Table
|
||||
border
|
||||
stripe
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
class="class-table"
|
||||
></Table>
|
||||
</div>
|
||||
<!-- 分页固定底部 -->
|
||||
<div class="pagination-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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑班级弹窗 -->
|
||||
<Modal v-model="modalVisible" :title="modalTitle" width="520">
|
||||
<Form ref="form" :model="formData" :rules="formRules" label-width="110">
|
||||
<FormItem label="班级代码">
|
||||
<Input v-model="formData.classCode" placeholder="请输入班级代码"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="班级名称" prop="className">
|
||||
<Input v-model="formData.className" placeholder="请输入班级名称"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="班级别名">
|
||||
<Input v-model="formData.alias" placeholder="请输入班级别名"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="所在校区">
|
||||
<Select v-model="formData.campus" placeholder="请选择校区" style="width:100%" transfer>
|
||||
<Option v-for="item in campusselectlist" :key="item.id" :value="item.id+''">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="所属系部" prop="dept">
|
||||
<Select v-model="formData.dept" placeholder="请选择系部" style="width:100%" transfer>
|
||||
<Option v-for="item in divisionselectlist" :key="item.id" :value="item.id+''">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="所属专业" prop="major">
|
||||
<Select v-model="formData.major" placeholder="请选择专业" style="width:100%" transfer>
|
||||
<Option v-for="item in majorsselectlist" :key="item.id" :value="item.id+''">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="班主任">
|
||||
<Select v-model="formData.teacher" placeholder="请选择班主任" style="width:100%" transfer>
|
||||
<Option v-for="item in teacherSelectlist" :key="item.id" :value="item.id+''">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="modalVisible = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitForm">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<!-- 班级信息导入 -->
|
||||
<Modal v-model="importModal" title="班级信息导入" width="560">
|
||||
<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 myTree from "../../components/my_tree";
|
||||
export default {
|
||||
name: 'HigherEducation',
|
||||
components: { myTree},
|
||||
data() {
|
||||
return {
|
||||
// 左侧树形数据
|
||||
treeData: [],
|
||||
selectnodeid: new Date().getFullYear()-1,
|
||||
|
||||
// 顶部筛选
|
||||
keyword: '',
|
||||
filterCampus: '',
|
||||
filterDept: '',
|
||||
filterMajor: '',
|
||||
|
||||
// 分页
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
|
||||
// 下拉选项数据源
|
||||
campusselectlist: [],
|
||||
divisionselectlist: [],
|
||||
majorsselectlist: [],
|
||||
teacherSelectlist: [],
|
||||
|
||||
// iView2 表格列配置(无TableColumn,columns标准写法)
|
||||
tableColumns: [
|
||||
{ title: '序号', type: 'index', align: 'center', width: 70 },
|
||||
{ title: '名称', key: 'name', align: 'center' },
|
||||
{ title: '编号', key: 'code', align: 'center' },
|
||||
{ title: '专业', key: 'majorsName', align: 'center' },
|
||||
{ title: '系部', key: 'divisionName', align: 'center' },
|
||||
{ title: '班主任', key: 'firstTeacherName', align: 'center' },
|
||||
{ title: '校区', key: 'campusName', align: 'center' },
|
||||
{ title: '别名', key: 'cname', align: 'center' },
|
||||
{ title: '年级', key: 'gradeName', align: 'center' },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
width: 130,
|
||||
render: (h, params) => {
|
||||
return h('div', { style: 'display:flex;gap:8px;justify-content:center' }, [
|
||||
h('Button', {
|
||||
props: { type: 'text', icon: 'ios-eye', size: 'large' },
|
||||
on: { click: () => this.viewDetail(params.row) }
|
||||
}),
|
||||
h('Button', {
|
||||
props: { type: 'text', icon: 'ios-create', size: 'large' },
|
||||
on: { click: () => this.editRow(params.row, params.index) }
|
||||
}),
|
||||
h('Button', {
|
||||
props: { type: 'text', icon: 'ios-trash', size: 'large' },
|
||||
on: { click: () => this.delRow(params.index) }
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
// 表格模拟数据
|
||||
tableData: [],
|
||||
UpParmas:{
|
||||
fileName:'',
|
||||
listData:{},
|
||||
datapre:{},
|
||||
actionUrl:APIConfig.BschClassSystem.importHeightClasses,
|
||||
columns:[
|
||||
{
|
||||
title: '行号',
|
||||
key: 'rows',
|
||||
align: 'center',
|
||||
width:'80'
|
||||
},
|
||||
{
|
||||
title: '内容',
|
||||
key: 'columnValue',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '错误详情',
|
||||
key: 'errorMsg',
|
||||
align: 'center',
|
||||
}
|
||||
],
|
||||
},
|
||||
|
||||
// 弹窗控制
|
||||
modalVisible: false,
|
||||
importModal:false,
|
||||
modalTitle: '',
|
||||
editIndex: null,
|
||||
formData: {
|
||||
classCode: '',
|
||||
className: '',
|
||||
alias: '',
|
||||
campus: '',
|
||||
dept: '',
|
||||
major: '',
|
||||
teacher: ''
|
||||
},
|
||||
formRules: {
|
||||
classCode: [{ required: true, message: '请输入班级代码', trigger: 'blur' }],
|
||||
className: [{ required: true, message: '请输入班级名称', trigger: 'blur' }],
|
||||
alias: [{ required: true, message: '请输入班级别名', trigger: 'blur' }],
|
||||
campus: [{ required: true, message: '请选择所在校区', trigger: 'change' }],
|
||||
dept: [{ required: true, message: '请选择所属系部', trigger: 'change' }],
|
||||
major: [{ required: true, message: '请选择所属专业', trigger: 'change' }],
|
||||
teacher: [{ required: true, message: '请选择班主任', trigger: 'change' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
uploadHeader() { //附件上传header
|
||||
let config = {};
|
||||
if (localStorage.getItem("currentRole")) {
|
||||
let currentRole = localStorage.getItem("currentRole");
|
||||
config["currentRole"] = currentRole;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
},
|
||||
created(){
|
||||
this.getGradeTree();
|
||||
this.getcampusselect();
|
||||
this.getdivisionselect();
|
||||
this.getmajorsselect();
|
||||
this.getteacherSelect();
|
||||
this.getsearcHigherSchClass();
|
||||
},
|
||||
methods: {
|
||||
//获取年级树
|
||||
getGradeTree:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getHigherSchGradeTree, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.treeData = resp.data;
|
||||
if(resp.data.children.length>0){
|
||||
// 起始节点为 data
|
||||
const pathArr = _this.getFirstPath(resp.data);
|
||||
_this.selectnodeid=pathArr[pathArr.length-1].id;
|
||||
}
|
||||
}else{
|
||||
_this.treeData=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取最后一级的map
|
||||
getFirstPath(rootNode) {
|
||||
const path = [];
|
||||
let cur = rootNode;
|
||||
while (cur) {
|
||||
// 存入当前层级关键信息
|
||||
path.push({
|
||||
id: cur.id,
|
||||
name: cur.name,
|
||||
type: cur.type,
|
||||
schsystemId:cur.schsystemId,
|
||||
gradeId:cur.gradeId,
|
||||
classId:cur.classId,
|
||||
});
|
||||
// 有子节点就取第一个,没有就终止
|
||||
if (cur.children && cur.children.length > 0) {
|
||||
cur = cur.children[0];
|
||||
} else {
|
||||
cur = null;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
},
|
||||
//节点点击事件
|
||||
treeLink(treeNode){
|
||||
this.selectnodeid=treeNode.id;
|
||||
this.getsearcHigherSchClass();
|
||||
},
|
||||
//校区下拉
|
||||
getcampusselect() {
|
||||
const _this = this;
|
||||
var item = {};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getcampusselect, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.campusselectlist = resp.data;
|
||||
} else {
|
||||
_this.campusselectlist = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
//系部下拉
|
||||
getdivisionselect() {
|
||||
const _this = this;
|
||||
var item = {};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getdivisionselect, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.divisionselectlist = resp.data;
|
||||
} else {
|
||||
_this.divisionselectlist = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
//专业下拉
|
||||
getmajorsselect() {
|
||||
const _this = this;
|
||||
var item = {};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getmajorsselect, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.majorsselectlist = resp.data;
|
||||
} else {
|
||||
_this.majorsselectlist = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
//教师下拉
|
||||
getteacherSelect:function(){
|
||||
const _this = this;
|
||||
var item={
|
||||
groupId:_this.deptFilter
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getteacherSelect, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.teacherSelectlist= resp.data;
|
||||
}else{
|
||||
_this.teacherSelectlist=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取班级列表
|
||||
getsearcHigherSchClass() {
|
||||
const _this = this;
|
||||
var item = {
|
||||
year:_this.selectnodeid,
|
||||
campusId:_this.filterCampus,
|
||||
divisionId:_this.filterDept,
|
||||
majorsId:_this.filterMajor,
|
||||
keyword:_this.keyword,
|
||||
page:_this.pageNum-1,
|
||||
size:_this.pageSize
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getsearcHigherSchClass, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.tableData = resp.data.content;
|
||||
_this.total=resp.data.total;
|
||||
} else {
|
||||
_this.tableData = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 搜索
|
||||
searchList() {
|
||||
this.pageNum = 1
|
||||
this.getsearcHigherSchClass();
|
||||
},
|
||||
|
||||
// 分页
|
||||
pageChange(page) {
|
||||
this.pageNum = page;
|
||||
this.getsearcHigherSchClass();
|
||||
},
|
||||
sizeChange(size) {
|
||||
this.pageSize = size
|
||||
this.pageNum = 1
|
||||
this.getsearcHigherSchClass();
|
||||
},
|
||||
|
||||
// 导入班级
|
||||
handleImport() {
|
||||
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.getsearcHigherSchClass();
|
||||
}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.downloadHeightTemplate+'?schId='+schId;
|
||||
window.location.href=url;
|
||||
}else{
|
||||
this.$Message.info('获取不了学校!');
|
||||
}
|
||||
},
|
||||
//附件上传模态框关闭事件
|
||||
UpfileModalcloseclick:function(){
|
||||
this.importModal=false;
|
||||
this.UpParmas={
|
||||
fileName:'',
|
||||
listData:{},
|
||||
datapre:{},
|
||||
}
|
||||
},
|
||||
|
||||
// 新增弹窗
|
||||
openAddModal() {
|
||||
this.editIndex = null
|
||||
this.modalTitle = '新增班级信息'
|
||||
this.formData = {
|
||||
classCode: '',
|
||||
className: '',
|
||||
alias: '',
|
||||
campus: '',
|
||||
dept: '',
|
||||
major: '',
|
||||
teacher: ''
|
||||
}
|
||||
this.modalVisible = true
|
||||
},
|
||||
|
||||
// 查看详情
|
||||
viewDetail(row) {
|
||||
this.$router.push('/ChristianityDetail?id='+row.id);
|
||||
},
|
||||
|
||||
// 编辑回填
|
||||
editRow(row, idx) {
|
||||
this.editIndex = idx
|
||||
this.modalTitle = '编辑班级信息'
|
||||
this.formData = {
|
||||
classCode: row.code,
|
||||
className: row.name,
|
||||
alias: row.cname,
|
||||
campus: row.campusId?row.campusId+'':'',
|
||||
dept: row.divisionId?row.divisionId+'':'',
|
||||
major: row.majorsId?row.majorsId+'':'',
|
||||
teacher:row.firstTeacherId?row.firstTeacherId+'':''
|
||||
}
|
||||
this.modalVisible = true
|
||||
},
|
||||
|
||||
// 删除
|
||||
delRow(idx) {
|
||||
this.$Modal.confirm({
|
||||
title:'提示',
|
||||
content:'确定删除该班级?',
|
||||
onOk:()=>{
|
||||
var url=APIConfig.BschClassSystem.deleteHigherSchClass+this.tableData[index].id;
|
||||
this.$api.post(url,{},(resp)=>{
|
||||
this.$Message.success('删除成功!');
|
||||
this.getsearcHigherSchClass();
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 提交表单
|
||||
submitForm() {
|
||||
this.$refs.form.validate(valid=>{
|
||||
if(!valid) return
|
||||
const form = this.formData
|
||||
if(this.editIndex === null) {
|
||||
// 新增
|
||||
const newItem = {
|
||||
code: form.classCode,
|
||||
name: form.className,
|
||||
cname: form.alias,
|
||||
campusId: form.campus,
|
||||
divisionId: form.dept,
|
||||
majorsId: form.major,
|
||||
firstTeacherId: form.teacher,
|
||||
enrollYear: this.selectnodeid
|
||||
}
|
||||
const url =APIConfig.BschClassSystem.saveHigherSchClass;
|
||||
this.$api.post(url, JSON.stringify(newItem), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("新增班级成功!");
|
||||
this.getsearcHigherSchClass();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 编辑
|
||||
const newItem = {
|
||||
id:this.tableData[this.editIndex].id,
|
||||
code: form.classCode,
|
||||
name: form.className,
|
||||
cname: form.alias,
|
||||
campusId: form.campus,
|
||||
divisionId: form.dept,
|
||||
majorsId: form.major,
|
||||
firstTeacherId: form.teacher,
|
||||
enrollYear: this.selectnodeid
|
||||
}
|
||||
const url =APIConfig.BschClassSystem.saveHigherSchClass;
|
||||
this.$api.post(url, JSON.stringify(newItem), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("编辑班级成功!");
|
||||
this.getsearcHigherSchClass();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.modalVisible = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 外层统一边框,和前面所有管理页面样式统一 */
|
||||
.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;
|
||||
}
|
||||
.page-container {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
gap: 16px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* 左侧树形区域 */
|
||||
.tree-left {
|
||||
width: 220px;
|
||||
border: 1px solid #e8e8e8;
|
||||
padding: 8px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* 右侧整体 */
|
||||
.right-main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* 顶部筛选栏 */
|
||||
.top-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
background: #f7f7f7;
|
||||
margin-bottom: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.btn-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
.filter-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 表格自适应容器 */
|
||||
.table-adapt-wrap {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-box {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.class-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 分页固定底部 */
|
||||
.pagination-bottom {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.total-text {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.ivu-alert-desc{
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<div class="oper-log-wrap">
|
||||
<!-- 顶部搜索栏 -->
|
||||
<div class="top-search-bar">
|
||||
<div></div>
|
||||
<div class="search-box">
|
||||
<Input
|
||||
v-model="searchKeyword"
|
||||
placeholder="请输入用户名、IP、模块或详细操作"
|
||||
search
|
||||
style="width:460px"
|
||||
@on-search="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自适应滚动表格容器 -->
|
||||
<div class="table-scroll-wrap">
|
||||
<Table
|
||||
border
|
||||
stripe
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
:height="useTableHeight()+32"
|
||||
></Table>
|
||||
</div>
|
||||
|
||||
<!-- 底部分栏:分页固定底部 -->
|
||||
<div class="page-bottom-bar">
|
||||
<div></div>
|
||||
<div class="page-wrap">
|
||||
<span style="margin-right:12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,50,100]"
|
||||
show-sizer
|
||||
@on-change="pageChange"
|
||||
@on-page-size-change="sizeChange"
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: 'OperationLogPage',
|
||||
data() {
|
||||
return {
|
||||
// 搜索关键词
|
||||
searchKeyword: '',
|
||||
|
||||
// 分页参数
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
|
||||
// 表格配置列
|
||||
tableColumns: [],
|
||||
// 模拟表格数据
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
mixins: [self_viewport],
|
||||
created() {
|
||||
this.initTableColumn()
|
||||
this.loadLogData()
|
||||
},
|
||||
methods: {
|
||||
// 初始化配置式表格列
|
||||
initTableColumn() {
|
||||
this.tableColumns = [
|
||||
{ title: '序号', type: 'index', align: 'center', width: 70 },
|
||||
{ title: '用户', key: 'operator', align: 'center', width: 130 },
|
||||
{ title: 'IP', key: 'ip', align: 'center', width: 150 },
|
||||
{ title: '模块', key: 'module', align: 'center', width: 160 },
|
||||
{ title: '详细操作', key: 'content', align: 'left' },
|
||||
{
|
||||
title: '时间',
|
||||
key: 'operateTime',
|
||||
align: 'center',
|
||||
width: 190,
|
||||
render: (h, params) => {
|
||||
return h("div", { style: "line-height: 56px" }, this.$utils.dateFormat(params.row.operateTime,'yyyy-MM-dd HH:mm:ss'));
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// 请求日志列表
|
||||
loadLogData() {
|
||||
const _this = this;
|
||||
var item = {
|
||||
keyword:_this.searchKeyword,
|
||||
page:_this.pageNum-1,
|
||||
size:_this.pageSize
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getlogsearch, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.tableData = resp.data.content;
|
||||
_this.total=resp.data.total;
|
||||
} else {
|
||||
_this.tableData = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.pageNum = 1
|
||||
this.loadLogData()
|
||||
},
|
||||
|
||||
// 页码切换
|
||||
pageChange(page) {
|
||||
this.pageNum = page
|
||||
this.loadLogData()
|
||||
},
|
||||
// 每页条数修改
|
||||
sizeChange(size) {
|
||||
this.pageSize = size
|
||||
this.pageNum = 1
|
||||
this.loadLogData()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.oper-log-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-bottom: 14px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.search-box {
|
||||
width: 100%;
|
||||
background: #f7f7f7;
|
||||
padding: 10px 16px;
|
||||
height: 52px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* 表格自适应滚动区域 */
|
||||
.table-scroll-wrap {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 底部分页固定栏 */
|
||||
.page-bottom-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 14px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.page-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,778 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<!-- 顶部标签栏 + 新增分组按钮 + 校本Tab编辑按钮 -->
|
||||
<div class="tab-header">
|
||||
<div class="tabs-wrap">
|
||||
<!-- 前两个固定Tab,无编辑按钮 -->
|
||||
<div
|
||||
class="tab-item fixed-tab"
|
||||
:class="{active: activeTab === '0'}"
|
||||
@click="activeTab = '0'"
|
||||
>
|
||||
拓展课选修班
|
||||
</div>
|
||||
<div
|
||||
class="tab-item fixed-tab"
|
||||
:class="{active: activeTab === '1'}"
|
||||
@click="activeTab = '1'"
|
||||
>
|
||||
走班
|
||||
</div>
|
||||
<!-- 动态可编辑校本Tab -->
|
||||
<div
|
||||
v-for="(tab, idx) in dynamicTabList"
|
||||
:key="tab.id"
|
||||
class="tab-item edit-tab"
|
||||
:class="{active: activeTab === tab.id}"
|
||||
@click="activeTab = tab.id"
|
||||
>
|
||||
{{ tab.name }}
|
||||
<Icon type="ios-create-outline" class="edit-icon" @click.stop="openEditGroupModal(tab, idx)"></Icon>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 加号新增校本分组 -->
|
||||
<Button icon="ios-add-circle-outline" class="add-tab-btn" @click="openAddGroupModal"></Button>
|
||||
</div>
|
||||
<!-- Tab下方全局分割线 -->
|
||||
<div class="tab-divider"></div>
|
||||
|
||||
<!-- 顶部操作按钮栏 -->
|
||||
<div class="btn-toolbar">
|
||||
<div class="left-btns">
|
||||
<Button type="primary" class="btn-normal" @click="openAddClassModal">添加班级</Button>
|
||||
<Button type="primary" class="btn-normal" @click="handleSyncClass">同步班级</Button>
|
||||
<Button type="success" class="btn-normal" @click="openImportClassModal">班级信息导入</Button>
|
||||
<Button type="success" class="btn-normal" @click="openImportStudentModal">学生导入</Button>
|
||||
</div>
|
||||
<div class="right-filter">
|
||||
<Select v-model="filterType" style="width:120px" class="filter-select">
|
||||
<Option value="other">其它</Option>
|
||||
</Select>
|
||||
<DatePicker
|
||||
placeholder="请选择开班时间"
|
||||
style="width:180px;margin-left:10px"
|
||||
v-model="filterOpenTime"
|
||||
></DatePicker>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格主体区域:自适应高度滚动,分页永久固定底部 -->
|
||||
<div class="table-wrap">
|
||||
<div class="table-scroll-box">
|
||||
<Table
|
||||
stripe
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
class="elective-table"
|
||||
@on-selection-change="onSelectionChange"
|
||||
height="100%"
|
||||
:border="false"
|
||||
></Table>
|
||||
</div>
|
||||
<!-- 底部分页+批量操作按钮 -->
|
||||
<div class="page-footer">
|
||||
<div class="batch-btns">
|
||||
<Button type="error" class="btn-bottom" @click="batchDelete" icon="ios-trash">删除</Button>
|
||||
<Button class="btn-bottom" style="margin-left:10px" @click="reSyncAll">重新同步</Button>
|
||||
</div>
|
||||
<div class="page-pagination">
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
:page-size.sync="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,50]"
|
||||
show-sizer
|
||||
show-total
|
||||
@on-change="loadTableData"
|
||||
@on-page-size-change="loadTableData"
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗1:新增校本分组 -->
|
||||
<Modal v-model="addGroupModal" title="添加组" width="420">
|
||||
<Form ref="groupForm" :model="groupForm" :rules="groupRules" label-width="80">
|
||||
<FormItem label="*组名称" prop="groupName">
|
||||
<Input v-model="groupForm.groupName" placeholder="请输入组名称"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="left">
|
||||
<Button type="error" @click="addGroupModal=false">删除</Button>
|
||||
<div style="float:right">
|
||||
<Button @click="addGroupModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitAddGroup">提交</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗2:编辑校本分组(对标截图红框弹窗) -->
|
||||
<Modal v-model="editGroupModal" title="编辑组" width="420">
|
||||
<Form ref="editGroupForm" :model="editGroupForm" :rules="editGroupRules" label-width="80">
|
||||
<FormItem label="*组名称" prop="groupName">
|
||||
<Input v-model="editGroupForm.groupName"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="left">
|
||||
<Button type="error" @click="confirmDelGroup">删除</Button>
|
||||
<div style="float:right">
|
||||
<Button @click="editGroupModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitEditGroup">提交</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗3:新增选修班 -->
|
||||
<Modal v-model="addClassModal" title="添加选修班" width="560">
|
||||
<Form ref="addClassForm" :model="addClassForm" :rules="addClassRules" label-width="100">
|
||||
<FormItem label="*班级名称" prop="className">
|
||||
<Input v-model="addClassForm.className" placeholder="请输入班级名称"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="*开班时间" prop="openTime">
|
||||
<DatePicker v-model="addClassForm.openTime" placeholder="请选择开班时间" style="width:100%"></DatePicker>
|
||||
</FormItem>
|
||||
<FormItem label="关班时间">
|
||||
<DatePicker v-model="addClassForm.closeTime" placeholder="请选择关班时间" style="width:100%"></DatePicker>
|
||||
</FormItem>
|
||||
<FormItem label="*选择教师" prop="teacherIds">
|
||||
<div style="display:flex;gap:8px;align-items:center;margin-bottom:8px;">
|
||||
<Select v-model="teacherQuery.subject" style="width:120px">
|
||||
<Option value="math">数学</Option>
|
||||
<Option value="chinese">语文</Option>
|
||||
<Option value="english">英语</Option>
|
||||
</Select>
|
||||
<Input v-model="teacherQuery.keyword" placeholder="请输入关键字" style="flex:1"></Input>
|
||||
<Button type="primary" @click="queryTeacherList">查询</Button>
|
||||
</div>
|
||||
<div class="teacher-btn-group">
|
||||
<Button
|
||||
v-for="item in teacherList"
|
||||
:key="item.id"
|
||||
size="small"
|
||||
:type="addClassForm.teacherIds.includes(item.id) ? 'primary' : 'default'"
|
||||
style="margin:4px"
|
||||
@click="toggleTeacherSelect(item)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</Button>
|
||||
</div>
|
||||
<div v-if="addClassForm.teacherIds.length>0" style="margin-top:8px">
|
||||
已选:
|
||||
<Tag
|
||||
v-for="tid in addClassForm.teacherIds"
|
||||
:key="tid"
|
||||
closable
|
||||
@on-close="removeTeacherTag(tid)"
|
||||
>
|
||||
{{ getTeacherNameById(tid) }}
|
||||
</Tag>
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem label="班级封面">
|
||||
<Upload action="" :before-upload="()=>false">
|
||||
<div class="upload-box">
|
||||
<Icon type="ios-add" size="24"></Icon>
|
||||
<p>+点击上传图片</p>
|
||||
</div>
|
||||
</Upload>
|
||||
</FormItem>
|
||||
<FormItem label="班级简介">
|
||||
<Input v-model="addClassForm.intro" type="textarea" rows="4" placeholder="请输入班级简介"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="计划招生人数">
|
||||
<Input v-model.number="addClassForm.studentNum" placeholder="请输入计划招生人数"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="addClassModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitAddClass">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗4:编辑选修班(完全匹配截图布局) -->
|
||||
<Modal v-model="editClassModal" title="编辑选修班" width="560">
|
||||
<Form ref="editClassForm" :model="editClassForm" :rules="addClassRules" label-width="100">
|
||||
<FormItem label="*班级名称" prop="className">
|
||||
<Input v-model="editClassForm.className"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="*开班时间" prop="openTime">
|
||||
<DatePicker v-model="editClassForm.openTime" style="width:100%"></DatePicker>
|
||||
</FormItem>
|
||||
<!-- 已选教师标签行 -->
|
||||
<div style="margin-bottom:8px;display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
|
||||
<span v-for="tid in editClassForm.teacherIds" :key="tid" style="display:flex;align-items:center;border:1px solid #ccc;padding:4px 8px;border-radius:4px;">
|
||||
:{{ getEditTeacherNameById(tid) }}
|
||||
<Icon type="ios-close" style="margin-left:6px;cursor:pointer;color:#666" @click="removeEditTeacherTag(tid)"/>
|
||||
</span>
|
||||
</div>
|
||||
<FormItem label="*任课教师" prop="teacherIds">
|
||||
<div style="display:flex;gap:8px;align-items:center;margin-bottom:8px;">
|
||||
<Select v-model="editTeacherQuery.subject" style="width:120px">
|
||||
<Option value="math">数学</Option>
|
||||
<Option value="chinese">语文</Option>
|
||||
<Option value="english">英语</Option>
|
||||
</Select>
|
||||
<Input v-model="editTeacherQuery.keyword" placeholder="请输入关键字" style="flex:1"></Input>
|
||||
<Button type="primary" @click="queryEditTeacherList">查询</Button>
|
||||
</div>
|
||||
<div class="teacher-btn-group">
|
||||
<Button
|
||||
v-for="item in editTeacherList"
|
||||
:key="item.id"
|
||||
size="small"
|
||||
:type="editClassForm.teacherIds.includes(item.id) ? 'primary' : 'default'"
|
||||
style="margin:4px"
|
||||
@click="toggleEditTeacherSelect(item)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</Button>
|
||||
</div>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="editClassModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitEditClass">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗5:班级信息导入 -->
|
||||
<Modal v-model="importClassModal" title="班级信息导入" width="440">
|
||||
<div style="margin-bottom:16px">
|
||||
<a href="javascript:;" style="color:#2d78f4">点击链接下载[班级导入模板.xls]</a>
|
||||
</div>
|
||||
<Upload action="" :before-upload="()=>false">
|
||||
<Button icon="ios-cloud-upload-outline">选择要上传的文件</Button>
|
||||
</Upload>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="importClassModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="confirmImportClass">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗6:学生导入 -->
|
||||
<Modal v-model="importStudentModal" title="学生导入" width="440">
|
||||
<div style="margin-bottom:16px">
|
||||
<a href="javascript:;" style="color:#2d78f4">点击链接下载[学生批量导入模板.xls]</a>
|
||||
</div>
|
||||
<Upload action="" :before-upload="()=>false">
|
||||
<Button icon="ios-cloud-upload-outline">选择要上传的文件</Button>
|
||||
</Upload>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="importStudentModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="confirmImportStudent">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 批量删除确认弹窗 -->
|
||||
<Modal v-model="delConfirmModal" title="提示" width="360">
|
||||
<Alert type="warning" show-icon>确认批量删除选中班级?删除后不可恢复</Alert>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="delConfirmModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="error" @click="confirmBatchDel">确定删除</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 删除分组二次确认弹窗 -->
|
||||
<Modal v-model="delGroupConfirmModal" title="删除分组提示" width="380">
|
||||
<Alert type="error" show-icon>确定删除该分组?分组下所有班级将会一并删除,不可恢复!</Alert>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="delGroupConfirmModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="error" @click="doDelGroup">确认删除</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "CurriculumElectiveClass",
|
||||
data() {
|
||||
return {
|
||||
// 激活选中项:0固定拓展课,1固定走班,其余为动态tab的id
|
||||
activeTab: "2",
|
||||
// 动态可编辑校本课程Tab列表,初始默认一条
|
||||
dynamicTabList: [
|
||||
{ id: "2", name: "校本课程" }
|
||||
],
|
||||
// 当前正在编辑的tab下标与对象
|
||||
editTabIndex: null,
|
||||
editTabItem: null,
|
||||
|
||||
// 筛选条件
|
||||
filterType: "other",
|
||||
filterOpenTime: null,
|
||||
|
||||
// 分页基础
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
total: 70,
|
||||
selectedRows: [], // 表格多选行
|
||||
|
||||
// 表格列配置:操作第一个改为编辑图标按钮
|
||||
tableColumns: [
|
||||
{ type: "selection", width: 50 },
|
||||
{ title: "#", type: "index", align: "center", width: 70 },
|
||||
{ title: "班级名称", key: "className", align: "left" },
|
||||
{ title: "开班时间", key: "openTime", align: "center", width: 160 },
|
||||
{ title: "教师", key: "teacherName", align: "center", width: 220 },
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
align: "center",
|
||||
width: 160,
|
||||
render: (h, params) => {
|
||||
return h("div", { style: "display:flex;gap:6px;justify-content:center" }, [
|
||||
// 第一个:编辑图标 打开编辑弹窗
|
||||
h("Button", {
|
||||
props: { type: "text", icon: "ios-create", size: "large" },
|
||||
on: { click: () => this.openEditClass(params.row) }
|
||||
}),
|
||||
// 学生管理
|
||||
h("Button", {
|
||||
props: { type: "text", icon: "ios-people", size: "large" },
|
||||
on: { click: () => this.openStudentManage(params.row) }
|
||||
}),
|
||||
// 同步刷新
|
||||
h("Button", {
|
||||
props: { type: "text", icon: "ios-refresh", size: "large" },
|
||||
on: { click: () => this.singleSync(params.row) }
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
],
|
||||
// 模拟表格数据
|
||||
tableData: [
|
||||
{ id: 1, className: "高一化学培优班", openTime: "2026-02-10", teacherName: "县晗", teacherIdList: [1] },
|
||||
{ id: 2, className: "排球", openTime: "2026-02-11", teacherName: "阮琳玮", teacherIdList: [2] },
|
||||
{ id: 3, className: "辩论与口才", openTime: "2026-02-12", teacherName: "蔡韵怡", teacherIdList: [3] },
|
||||
{ id: 4, className: "银行实务&经济学原理简析", openTime: "2026-02-13", teacherName: "任蕾,吕婷", teacherIdList: [4,5] },
|
||||
{ id: 5, className: "叩问与回响:经典短篇小说的细读与鉴赏", openTime: "2026-02-14", teacherName: "韩佳慧", teacherIdList: [6] },
|
||||
{ id: 6, className: "叙事的镜子:文学与其影视改编", openTime: "2026-02-15", teacherName: "李嘉萱", teacherIdList: [7] },
|
||||
{ id: 7, className: "寻迹\"唐宋八大家\"", openTime: "2026-02-16", teacherName: "苏煦雯", teacherIdList: [8] },
|
||||
{ id: 8, className: "高二数学基础班", openTime: "2026-02-17", teacherName: "蓝怡", teacherIdList: [9] }
|
||||
],
|
||||
|
||||
// ========== 添加分组弹窗 ==========
|
||||
addGroupModal: false,
|
||||
groupForm: { groupName: "" },
|
||||
groupRules: { groupName: [{ required: true, message: "请输入组名称", trigger: "blur" }] },
|
||||
|
||||
// ========== 编辑分组弹窗(对标截图) ==========
|
||||
editGroupModal: false,
|
||||
editGroupForm: { groupName: "" },
|
||||
editGroupRules: { groupName: [{ required: true, message: "请输入组名称", trigger: "blur" }] },
|
||||
delGroupConfirmModal: false,
|
||||
|
||||
// ========== 新增班级弹窗 ==========
|
||||
addClassModal: false,
|
||||
addClassForm: {
|
||||
className: "",
|
||||
openTime: null,
|
||||
closeTime: null,
|
||||
teacherIds: [],
|
||||
intro: "",
|
||||
studentNum: null
|
||||
},
|
||||
addClassRules: {
|
||||
className: [{ required: true, message: "请填写班级名称", trigger: "blur" }],
|
||||
openTime: [{ required: true, message: "请选择开班时间", trigger: "change" }],
|
||||
teacherIds: [{ required: true, message: "请至少选择一位任课教师", trigger: "change" }]
|
||||
},
|
||||
teacherQuery: { subject: "math", keyword: "" },
|
||||
teacherList: [],
|
||||
|
||||
// ========== 编辑班级弹窗 ==========
|
||||
editClassModal: false,
|
||||
editCurrentRow: null,
|
||||
editClassForm: {
|
||||
className: "",
|
||||
openTime: null,
|
||||
teacherIds: []
|
||||
},
|
||||
editTeacherQuery: { subject: "math", keyword: "" },
|
||||
editTeacherList: [],
|
||||
|
||||
// ========== 导入弹窗 ==========
|
||||
importClassModal: false,
|
||||
importStudentModal: false,
|
||||
// 批量删除确认
|
||||
delConfirmModal: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadTableData();
|
||||
},
|
||||
methods: {
|
||||
// 加载表格分页数据
|
||||
loadTableData() {
|
||||
console.log("分页查询参数", {
|
||||
page: this.pageNum,
|
||||
size: this.pageSize,
|
||||
tabId: this.activeTab,
|
||||
filter: this.filterType,
|
||||
time: this.filterOpenTime
|
||||
});
|
||||
// 此处替换后端接口赋值tableData、total
|
||||
},
|
||||
// 表格多选
|
||||
onSelectionChange(rows) {
|
||||
this.selectedRows = rows;
|
||||
},
|
||||
|
||||
// 打开【新增校本分组】弹窗
|
||||
openAddGroupModal() {
|
||||
this.addGroupModal = true;
|
||||
this.groupForm.groupName = "";
|
||||
this.$nextTick(() => this.$refs.groupForm.clearValidate());
|
||||
},
|
||||
// 提交新增分组
|
||||
submitAddGroup() {
|
||||
this.$refs.groupForm.validate(valid => {
|
||||
if (!valid) return;
|
||||
const newId = Date.now().toString();
|
||||
this.dynamicTabList.push({
|
||||
id: newId,
|
||||
name: this.groupForm.groupName
|
||||
})
|
||||
this.activeTab = newId;
|
||||
this.$Message.success("分组新增成功");
|
||||
this.addGroupModal = false;
|
||||
this.loadTableData();
|
||||
})
|
||||
},
|
||||
|
||||
// 打开【编辑组】弹窗(点击Tab右上角铅笔图标)
|
||||
openEditGroupModal(tabItem, index) {
|
||||
this.editTabItem = tabItem;
|
||||
this.editTabIndex = index;
|
||||
this.editGroupForm.groupName = tabItem.name;
|
||||
this.editGroupModal = true;
|
||||
this.$nextTick(() => this.$refs.editGroupForm.clearValidate());
|
||||
},
|
||||
// 提交编辑分组名称
|
||||
submitEditGroup() {
|
||||
this.$refs.editGroupForm.validate(valid => {
|
||||
if (!valid) return;
|
||||
this.dynamicTabList[this.editTabIndex].name = this.editGroupForm.groupName;
|
||||
this.$Message.success("分组名称修改成功");
|
||||
this.editGroupModal = false;
|
||||
})
|
||||
},
|
||||
// 点击弹窗删除按钮,弹出二次确认
|
||||
confirmDelGroup() {
|
||||
this.editGroupModal = false;
|
||||
this.delGroupConfirmModal = true;
|
||||
},
|
||||
// 真正执行删除分组
|
||||
doDelGroup() {
|
||||
this.dynamicTabList.splice(this.editTabIndex, 1);
|
||||
// 如果删的是当前激活tab,默认切到第一个动态tab
|
||||
if (this.activeTab === this.editTabItem.id && this.dynamicTabList.length) {
|
||||
this.activeTab = this.dynamicTabList[0].id;
|
||||
} else if (!this.dynamicTabList.length) {
|
||||
this.activeTab = "0";
|
||||
}
|
||||
this.delGroupConfirmModal = false;
|
||||
this.$Message.success("分组已删除");
|
||||
this.loadTableData();
|
||||
},
|
||||
|
||||
// 2. 添加班级
|
||||
openAddClassModal() {
|
||||
this.addClassModal = true;
|
||||
this.addClassForm = {
|
||||
className: "", openTime: null, closeTime: null, teacherIds: [], intro: "", studentNum: null
|
||||
};
|
||||
this.teacherList = [];
|
||||
this.teacherQuery = { subject: "math", keyword: "" };
|
||||
this.$nextTick(() => this.$refs.addClassForm.clearValidate());
|
||||
},
|
||||
// 查询教师列表
|
||||
queryTeacherList() {
|
||||
// 模拟接口返回教师数组
|
||||
this.teacherList = [
|
||||
{ id: 1, name: "陶为玉" }, { id: 2, name: "丁雪芬" }, { id: 3, name: "贺少君" },
|
||||
{ id: 4, name: "金添玉" }, { id: 5, name: "田雪婷" }, { id: 6, name: "金慧" },
|
||||
{ id: 7, name: "翁海红" }, { id: 8, name: "钱李铭" }, { id: 9, name: "邱侯晗" },
|
||||
{ id: 10, name: "沈裴裴" }, { id: 11, name: "左惊喜" }, { id: 12, name: "东昌测试1" },
|
||||
{ id: 13, name: "苏煦雯" }, { id: 14, name: "李嘉萱" }, { id: 15, name: "王心洁" },
|
||||
{ id: 16, name: "蓝怡" }, { id: 17, name: "鄢泓" }, { id: 18, name: "颜国连" }
|
||||
];
|
||||
},
|
||||
// 切换教师勾选
|
||||
toggleTeacherSelect(item) {
|
||||
const idx = this.addClassForm.teacherIds.indexOf(item.id);
|
||||
if (idx > -1) {
|
||||
this.addClassForm.teacherIds.splice(idx, 1);
|
||||
} else {
|
||||
this.addClassForm.teacherIds.push(item.id);
|
||||
}
|
||||
},
|
||||
removeTeacherTag(tid) {
|
||||
const i = this.addClassForm.teacherIds.indexOf(tid);
|
||||
if (i > -1) this.addClassForm.teacherIds.splice(i, 1);
|
||||
},
|
||||
getTeacherNameById(tid) {
|
||||
const t = this.teacherList.find(s => s.id === tid);
|
||||
return t ? t.name : "";
|
||||
},
|
||||
submitAddClass() {
|
||||
this.$refs.addClassForm.validate(valid => {
|
||||
if (!valid) return;
|
||||
this.$Message.success("新增选修班成功");
|
||||
this.addClassModal = false;
|
||||
this.loadTableData();
|
||||
})
|
||||
},
|
||||
|
||||
// 3. 编辑班级(行编辑按钮触发)
|
||||
openEditClass(row) {
|
||||
this.editCurrentRow = row;
|
||||
this.editClassModal = true;
|
||||
this.editClassForm = {
|
||||
className: row.className,
|
||||
openTime: row.openTime,
|
||||
teacherIds: row.teacherIdList || []
|
||||
};
|
||||
this.editTeacherList = [];
|
||||
this.editTeacherQuery = { subject: "math", keyword: "" };
|
||||
this.$nextTick(() => this.$refs.editClassForm.clearValidate());
|
||||
},
|
||||
queryEditTeacherList() {
|
||||
// 匹配截图教师列表
|
||||
this.editTeacherList = [
|
||||
{ id: 101, name: "薛志明" }, { id: 102, name: "金瑜" }, { id: 103, name: "向荣" }, { id: 104, name: "张锦花" },
|
||||
{ id: 105, name: "周慧敏" }, { id: 106, name: "张凌敏" }, { id: 107, name: "孙丽杰" }, { id: 108, name: "乔瑜" },
|
||||
{ id: 109, name: "潘悦" }, { id: 110, name: "强熙" }, { id: 111, name: "张静漪" }, { id: 112, name: "杨雪" },
|
||||
{ id: 113, name: "陈梦舟" }, { id: 114, name: "解颖" }, { id: 115, name: "施瑞安" }, { id: 116, name: "殷继宗" },
|
||||
{ id: 117, name: "王恩跃" }, { id: 118, name: "徐丽丽" }, { id: 119, name: "吴萍" }, { id: 120, name: "王妍婷" }
|
||||
];
|
||||
},
|
||||
toggleEditTeacherSelect(item) {
|
||||
const idx = this.editClassForm.teacherIds.indexOf(item.id);
|
||||
if (idx > -1) this.editClassForm.teacherIds.splice(idx, 1);
|
||||
else this.editClassForm.teacherIds.push(item.id);
|
||||
},
|
||||
removeEditTeacherTag(tid) {
|
||||
const i = this.editClassForm.teacherIds.indexOf(tid);
|
||||
if (i > -1) this.editClassForm.teacherIds.splice(i, 1);
|
||||
},
|
||||
getEditTeacherNameById(tid) {
|
||||
const t = this.editTeacherList.find(s => s.id === tid);
|
||||
return t ? t.name : "";
|
||||
},
|
||||
submitEditClass() {
|
||||
this.$refs.editClassForm.validate(valid => {
|
||||
if (!valid) return;
|
||||
this.$Message.success("编辑班级成功");
|
||||
this.editClassModal = false;
|
||||
this.loadTableData();
|
||||
})
|
||||
},
|
||||
|
||||
// 导入弹窗
|
||||
openImportClassModal() { this.importClassModal = true; },
|
||||
confirmImportClass() {
|
||||
this.$Message.success("班级导入完成");
|
||||
this.importClassModal = false;
|
||||
this.loadTableData();
|
||||
},
|
||||
openImportStudentModal() { this.importStudentModal = true; },
|
||||
confirmImportStudent() {
|
||||
this.$Message.success("学生导入完成");
|
||||
this.importStudentModal = false;
|
||||
},
|
||||
|
||||
// 顶部按钮:同步班级
|
||||
handleSyncClass() {
|
||||
this.$Message.success("同步班级操作完成");
|
||||
this.loadTableData();
|
||||
},
|
||||
// 底部:重新同步全部
|
||||
reSyncAll() {
|
||||
this.$Message.success("全局重新同步完成");
|
||||
this.loadTableData();
|
||||
},
|
||||
// 单条行内同步
|
||||
singleSync(row) {
|
||||
this.$Message.success(`【${row.className}】同步成功`);
|
||||
},
|
||||
// 学生管理
|
||||
openStudentManage(row) {
|
||||
this.$router.push({path:'/electiveClassManageDetail'});
|
||||
},
|
||||
|
||||
// 批量删除
|
||||
batchDelete() {
|
||||
if (!this.selectedRows.length) return this.$Message.warning("请先勾选要删除的班级");
|
||||
this.delConfirmModal = true;
|
||||
},
|
||||
confirmBatchDel() {
|
||||
this.$Message.success("批量删除成功");
|
||||
this.delConfirmModal = false;
|
||||
this.selectedRows = [];
|
||||
this.loadTableData();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
gap: 14px;
|
||||
}
|
||||
/* 顶部Tab栏整体布局 */
|
||||
.tab-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.tabs-wrap {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
/* Tab核心样式:仅底部下划线选中,无边框无背景 */
|
||||
.tab-item {
|
||||
padding: 8px 16px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
border: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
background: transparent;
|
||||
margin-right: 4px;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.tab-item.active {
|
||||
background: transparent;
|
||||
border-top: none;
|
||||
border-bottom: 2px solid #3377dd;
|
||||
font-weight: 500;
|
||||
}
|
||||
.fixed-tab {
|
||||
cursor: default;
|
||||
}
|
||||
.edit-icon {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
}
|
||||
.add-tab-btn {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
padding: 0;
|
||||
}
|
||||
/* Tab下方通栏分割线 */
|
||||
.tab-divider {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #dcdcdc;
|
||||
}
|
||||
/* 顶部按钮工具栏 */
|
||||
.btn-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
background: #f7f8fa;
|
||||
border-radius: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.left-btns {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
.btn-normal {
|
||||
padding: 6px 14px;
|
||||
}
|
||||
.filter-select {
|
||||
margin-right: 8px;
|
||||
}
|
||||
/* 表格自适应容器,移除外层边框 */
|
||||
.table-wrap {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
.table-scroll-box {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.elective-table {
|
||||
width: 100%;
|
||||
}
|
||||
/* 底部分页与按钮 */
|
||||
.page-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 14px 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.batch-btns {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.btn-bottom {
|
||||
padding: 6px 16px;
|
||||
}
|
||||
/* 教师多选按钮组 */
|
||||
.teacher-btn-group {
|
||||
max-height: 180px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #e5e7eb;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
/* 上传封面框 */
|
||||
.upload-box {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border: 1px dashed #ccc;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #999;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
/* 全局穿透修改iView表格,完全匹配截图:无外框、无竖线、仅行底横线 */
|
||||
/deep/ .ivu-table {
|
||||
border: none !important;
|
||||
}
|
||||
/deep/ .ivu-table-header th {
|
||||
border: none;
|
||||
border-bottom: 1px solid #eee;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
}
|
||||
/deep/ .ivu-table td {
|
||||
border-left: none !important;
|
||||
border-right: none !important;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
/deep/ .ivu-table-row {
|
||||
border: none;
|
||||
}
|
||||
/deep/ .ivu-table-stripe .ivu-table-row:nth-child(even) {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,345 @@
|
||||
<template>
|
||||
<div class="student-class-page">
|
||||
<!-- 顶部标题栏 -->
|
||||
<div class="page-top-bar">
|
||||
<span class="current-class-txt">当前班级:{{ currentClassName }}</span>
|
||||
<Button type="primary" @click="backPrevPage">返回上一级</Button>
|
||||
</div>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<div class="tool-bar">
|
||||
<span class="list-title">学生列表</span>
|
||||
<div class="btn-group">
|
||||
<Button type="primary" @click="openTransferModal">调班</Button>
|
||||
<Button type="success" @click="openStudentImportModal">学生导入</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格区域 自适应高度滚动 -->
|
||||
<div class="table-wrap">
|
||||
<div class="table-scroll-box">
|
||||
<Table
|
||||
stripe
|
||||
:columns="tableColumns"
|
||||
:data="studentTableData"
|
||||
height="100%"
|
||||
:border="false"
|
||||
@on-selection-change="onTableSelect"
|
||||
></Table>
|
||||
</div>
|
||||
<!-- 底栏:批量删除 + 分页 -->
|
||||
<div class="page-footer">
|
||||
<Button type="error" @click="batchDelConfirm">删除</Button>
|
||||
<div class="pagination-box">
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
:page-size.sync="pageSize"
|
||||
:total="totalCount"
|
||||
:page-size-opts="[10,20,50]"
|
||||
show-sizer
|
||||
show-total
|
||||
@on-change="loadStudentData"
|
||||
@on-page-size-change="loadStudentData"
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗1:调班弹窗 -->
|
||||
<Modal v-model="transferModal" title="调班" width="680">
|
||||
<Form label-width="100">
|
||||
<FormItem label="当前班级">
|
||||
<Input v-model="currentClassName" disabled></Input>
|
||||
</FormItem>
|
||||
<FormItem label="*目标班级">
|
||||
<div class="transfer-search-row">
|
||||
<Select v-model="transferQuery.grade" placeholder="请选择" style="width:140px">
|
||||
<Option value="g1">高一</Option>
|
||||
<Option value="g2">高二</Option>
|
||||
<Option value="g3">高三</Option>
|
||||
</Select>
|
||||
<Input v-model="transferQuery.keyword" placeholder="请输入关键字" style="flex:1;margin:0 10px"></Input>
|
||||
<Button type="primary" @click="queryTargetClassList">查询</Button>
|
||||
</div>
|
||||
<div class="class-btn-box">
|
||||
<Button
|
||||
v-for="item in targetClassList"
|
||||
:key="item.id"
|
||||
size="small"
|
||||
:type="selectedTargetId === item.id ? 'primary' : 'default'"
|
||||
style="margin:6px"
|
||||
@click="selectedTargetId = item.id"
|
||||
>
|
||||
{{ item.name }}
|
||||
</Button>
|
||||
</div>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="transferModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="confirmTransferStudent">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗2:学生信息导入 -->
|
||||
<Modal v-model="importModal" title="学生信息导入" width="460">
|
||||
<div style="margin-bottom:16px;">
|
||||
<a href="javascript:;" style="color:#2d78f4">点击链接下载[用户导入模板.xls]</a>
|
||||
</div>
|
||||
<Upload action="" :before-upload="()=>false">
|
||||
<Button icon="ios-cloud-upload-outline">选择要上传的文件</Button>
|
||||
</Upload>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="importModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="confirmImport">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 批量删除二次确认弹窗 -->
|
||||
<Modal v-model="delConfirmModal" title="提示" width="360">
|
||||
<Alert type="warning" show-icon>确认删除选中学生?删除后不可恢复</Alert>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="delConfirmModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="error" @click="doBatchDelete">确定删除</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "ClassStudentManage",
|
||||
props: {
|
||||
// 父页面传入当前班级名称与班级ID
|
||||
classId: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: "高一化学培优班"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 班级信息
|
||||
currentClassName: this.className,
|
||||
// 分页
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 19,
|
||||
// 表格多选
|
||||
selectedStudentRows: [],
|
||||
// 表格列配置
|
||||
tableColumns: [
|
||||
{ type: "selection", width: 50 },
|
||||
{ title: "序号", type: "index", align: "center", width: 70 },
|
||||
{ title: "姓名", key: "name", align: "left" },
|
||||
{ title: "年级", key: "grade", align: "center" },
|
||||
{ title: "班级", key: "originClass", align: "center" }
|
||||
],
|
||||
// 模拟学生列表数据
|
||||
studentTableData: [
|
||||
{ id: 1, name: "潘程", grade: "高一", originClass: "2班" },
|
||||
{ id: 2, name: "张译匀", grade: "高一", originClass: "9班" },
|
||||
{ id: 3, name: "宋浩扬", grade: "高一", originClass: "1班" },
|
||||
{ id: 4, name: "裴劲丰", grade: "高一", originClass: "8班" },
|
||||
{ id: 5, name: "余知新", grade: "高一", originClass: "8班" },
|
||||
{ id: 6, name: "刘翰城", grade: "高一", originClass: "14班" },
|
||||
{ id: 7, name: "于释涵", grade: "高一", originClass: "11班" },
|
||||
{ id: 8, name: "王梦菡", grade: "高一", originClass: "13班" }
|
||||
],
|
||||
|
||||
// 调班弹窗
|
||||
transferModal: false,
|
||||
transferQuery: {
|
||||
grade: "",
|
||||
keyword: ""
|
||||
},
|
||||
targetClassList: [],
|
||||
selectedTargetId: null,
|
||||
|
||||
// 导入弹窗
|
||||
importModal: false,
|
||||
// 删除确认弹窗
|
||||
delConfirmModal: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadStudentData()
|
||||
},
|
||||
methods: {
|
||||
// 返回上一级(父级选修班列表页)
|
||||
backPrevPage() {
|
||||
this.$router.back()
|
||||
},
|
||||
// 加载学生分页列表
|
||||
loadStudentData() {
|
||||
console.log('请求参数', {
|
||||
classId: this.classId,
|
||||
page: this.pageNum,
|
||||
size: this.pageSize
|
||||
})
|
||||
// 此处替换后端接口赋值 studentTableData、totalCount
|
||||
},
|
||||
// 表格多选事件
|
||||
onTableSelect(rows) {
|
||||
this.selectedStudentRows = rows
|
||||
},
|
||||
|
||||
// 打开调班弹窗
|
||||
openTransferModal() {
|
||||
if (!this.selectedStudentRows.length) {
|
||||
return this.$Message.warning("请先勾选需要调班的学生")
|
||||
}
|
||||
this.transferModal = true
|
||||
this.transferQuery = { grade: "", keyword: "" }
|
||||
this.selectedTargetId = null
|
||||
this.targetClassList = []
|
||||
},
|
||||
// 查询目标可选班级
|
||||
queryTargetClassList() {
|
||||
// 模拟接口返回下拉班级列表
|
||||
this.targetClassList = [
|
||||
{ id: 1, name: "高三网球1班(2024学年)" },
|
||||
{ id: 2, name: "高三排球1班(2024学年)" },
|
||||
{ id: 3, name: "高三女篮1班 (2024学年)" },
|
||||
{ id: 4, name: "高三男篮1班 (2024学年)" },
|
||||
{ id: 5, name: "高三羽毛球1班 (2024学年)" },
|
||||
{ id: 6, name: "高三足球1班 (2024学年)" },
|
||||
{ id: 7, name: "高三乒乓球1班(2024学年)" },
|
||||
{ id: 8, name: "高三网球2班(2024学年)" },
|
||||
{ id: 9, name: "高三排球2班(2024学年)" },
|
||||
{ id: 10, name: "高三足球2班(2024学年)" }
|
||||
]
|
||||
},
|
||||
// 确认执行调班
|
||||
confirmTransferStudent() {
|
||||
if (!this.selectedTargetId) {
|
||||
return this.$Message.warning("请选择目标班级")
|
||||
}
|
||||
this.$Message.success("学生调班完成")
|
||||
this.transferModal = false
|
||||
this.loadStudentData()
|
||||
},
|
||||
|
||||
// 打开导入弹窗
|
||||
openStudentImportModal() {
|
||||
this.importModal = true
|
||||
},
|
||||
confirmImport() {
|
||||
this.$Message.success("学生导入成功")
|
||||
this.importModal = false
|
||||
this.loadStudentData()
|
||||
},
|
||||
|
||||
// 批量删除
|
||||
batchDelConfirm() {
|
||||
if (!this.selectedStudentRows.length) {
|
||||
return this.$Message.warning("请勾选要删除的学生")
|
||||
}
|
||||
this.delConfirmModal = true
|
||||
},
|
||||
doBatchDelete() {
|
||||
this.$Message.success("批量删除成功")
|
||||
this.delConfirmModal = false
|
||||
this.selectedStudentRows = []
|
||||
this.loadStudentData()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.student-class-page {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
gap: 16px;
|
||||
}
|
||||
/* 顶部标题栏 */
|
||||
.page-top-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.current-class-txt {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
/* 工具栏 */
|
||||
.tool-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 12px;
|
||||
background: #f7f8fa;
|
||||
}
|
||||
.list-title {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.btn-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
/* 表格容器 自适应高度 */
|
||||
.table-wrap {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-box {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
/* 底部分页栏 */
|
||||
.page-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
/* 调班弹窗查询行 */
|
||||
.transfer-search-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.class-btn-box {
|
||||
max-height: 220px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #e5e7eb;
|
||||
padding: 8px;
|
||||
margin-top: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
/* 全局穿透 表格样式 与截图一致:无外框无竖线,仅行底横线 */
|
||||
/deep/ .ivu-table {
|
||||
border: none !important;
|
||||
}
|
||||
/deep/ .ivu-table-header th {
|
||||
border: none;
|
||||
border-bottom: 1px solid #eee;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
}
|
||||
/deep/ .ivu-table td {
|
||||
border-left: none !important;
|
||||
border-right: none !important;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
/deep/ .ivu-table-row {
|
||||
border: none;
|
||||
}
|
||||
/deep/ .ivu-table-stripe .ivu-table-row:nth-child(even) {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,338 @@
|
||||
<template>
|
||||
<div class="class-history-wrap">
|
||||
<!-- 左侧树形区域:固定高度纵向滚动、单选、默认首班级选中 -->
|
||||
<div class="left-tree-box">
|
||||
<Tree
|
||||
:data="treeData"
|
||||
ref="tree"
|
||||
single
|
||||
:selected.sync="selectedTreeNode"
|
||||
@on-select="treeNodeChange"
|
||||
></Tree>
|
||||
</div>
|
||||
|
||||
<!-- 右侧主内容区域 -->
|
||||
<div class="right-main">
|
||||
<!-- 顶部基础信息栏 -->
|
||||
<div class="top-info-bar">
|
||||
<span class="info-item">学级:{{ currentGrade }}</span>
|
||||
<span class="info-item">班级:{{ currentClassName }}</span>
|
||||
<span class="info-item">入学时间:{{ enrollDate }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 标签页切换:历史任教 / 历史学生 -->
|
||||
<Tabs v-model="activeTab">
|
||||
<TabPane label="历史任教" name="teach"></TabPane>
|
||||
<TabPane label="历史学生" name="student"></TabPane>
|
||||
</Tabs>
|
||||
|
||||
<!-- 筛选头部行 -->
|
||||
<div class="filter-bar">
|
||||
<span>日期:{{ dateRange }} 年级:{{ currentGradeShort }}</span>
|
||||
<span v-if="activeTab === 'student'" style="margin-left:20px">学生数:{{ studentTotal }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 滚动内容容器:高度自适应溢出滚动 -->
|
||||
<div class="scroll-content-box">
|
||||
<!-- 历史任教布局 -->
|
||||
<div v-if="activeTab === 'teach'" class="teach-wrap">
|
||||
<div class="item-card" v-for="(item,idx) in teachList" :key="idx">
|
||||
<div class="card-title">{{ item.subject }}</div>
|
||||
<div class="card-value">{{ item.teacher }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 历史学生布局 -->
|
||||
<div v-if="activeTab === 'student'" class="student-wrap">
|
||||
<div class="item-card student-card" style="cursor: pointer;" v-for="(item,idx) in studentList" :key="idx" @click="tolink(item)">
|
||||
{{ item.name }}<span v-if="item.idCard">({{ item.idCard }})</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部分页固定区域(预留分页逻辑) -->
|
||||
<div class="page-bottom-bar">
|
||||
<span>共 {{ activeTab === 'teach' ? teachList.length : studentTotal }} 条</span>
|
||||
<Page
|
||||
v-if="needPage"
|
||||
:current.sync="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="activeTab === 'teach' ? teachList.length : studentTotal"
|
||||
:page-size-opts="[20,40,60]"
|
||||
show-sizer
|
||||
@on-change="pageChange"
|
||||
@on-page-size-change="sizeChange"
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ClassHistoryPage',
|
||||
data() {
|
||||
return {
|
||||
// 树形配置
|
||||
treeData: [
|
||||
{
|
||||
title: '上海市进才中学北校',
|
||||
expand: true,
|
||||
children: [
|
||||
{
|
||||
title: '2025级(预备)',
|
||||
expand: true,
|
||||
children: [
|
||||
{ title: '1班' },{ title: '2班' },{ title: '3班' },{ title: '4班' },{ title: '5班' },
|
||||
{ title: '6班' },{ title: '7班' },{ title: '8班' },{ title: '9班' },{ title: '10班' },
|
||||
{ title: '11班' },{ title: '12班' },{ title: '13班' },{ title: '14班' },{ title: '15班' },
|
||||
{ title: '16班' },{ title: '17班' },{ title: '18班' },{ title: '19班' },{ title: '20班' },
|
||||
{ title: '21班' },{ title: '22班' },{ title: '23班' },
|
||||
]
|
||||
},
|
||||
{ title: '2024级(初一)', expand: true, children: [] },
|
||||
{ title: '2023级(初二)', expand: true, children: [] },
|
||||
]
|
||||
}
|
||||
],
|
||||
selectedTreeNode: null,
|
||||
currentClassName: '1班',
|
||||
currentGrade: '2025级',
|
||||
currentGradeShort: '预备',
|
||||
enrollDate: '2025-07-11',
|
||||
dateRange: '2025-07-11 - 2026-07-15',
|
||||
|
||||
// 标签页
|
||||
activeTab: 'teach',
|
||||
|
||||
// 任教数据
|
||||
teachList: [
|
||||
{ subject: '班主任', teacher: '伍芳芳' },
|
||||
{ subject: '语文', teacher: '卫红' },
|
||||
{ subject: '数学', teacher: '伍芳芳' },
|
||||
{ subject: '英语', teacher: '俞莉玉' },
|
||||
{ subject: '体育', teacher: '郑浩淼' },
|
||||
{ subject: '美术', teacher: '蔡婷婷' },
|
||||
{ subject: '科学', teacher: '游宝玲' },
|
||||
{ subject: '劳技', teacher: '牛乐' },
|
||||
{ subject: '地理', teacher: '沈晓燕' },
|
||||
{ subject: '音乐', teacher: '李海昆' },
|
||||
{ subject: '心理', teacher: '展望' },
|
||||
{ subject: '道德与法治', teacher: '郭雨佳' },
|
||||
{ subject: '班主任', teacher: '伍芳芳' },
|
||||
{ subject: '劳动', teacher: '牛乐' },
|
||||
{ subject: '信息科技', teacher: '张颖' },
|
||||
{ subject: '副班主任', teacher: '展望' },
|
||||
{ subject: '校本(劳动教育)', teacher: '牛乐' },
|
||||
{ subject: '体育与健康', teacher: '郑浩淼' },
|
||||
{ subject: '二外', teacher: '季思飞' },
|
||||
{ subject: '校本(心理+二外)', teacher: '数字化中心09' },
|
||||
],
|
||||
|
||||
// 学生数据
|
||||
studentTotal: 48,
|
||||
studentList: [
|
||||
{ name: '金俊辰', idCard: '' },
|
||||
{ name: '周泽恒', idCard: '310115201404031836' },
|
||||
{ name: '杨城宁', idCard: '310115201406110407' },
|
||||
{ name: '李琪琪', idCard: '310115201403072281' },
|
||||
{ name: '浦森隽', idCard: '310115201311290011' },
|
||||
{ name: '沈奕欣', idCard: '310115201402286384' },
|
||||
{ name: '李赛乐', idCard: '31011520131110037X' },
|
||||
{ name: '林欣宜', idCard: '310109201403261560' },
|
||||
{ name: '胡艺涵', idCard: '310115201403251167' },
|
||||
{ name: '周维哲', idCard: '310115201311182221' },
|
||||
{ name: '曹维德', idCard: '310115201311182213' },
|
||||
{ name: '陈茂萌', idCard: '310115201406020516' },
|
||||
{ name: '施锐朗', idCard: '31011520140412491X' },
|
||||
{ name: '袁唯格', idCard: '310115201401270022' },
|
||||
{ name: '徐睿辰', idCard: '310115201406284490' },
|
||||
{ name: '姚欣蕊', idCard: '310115201402161848' },
|
||||
{ name: '王立仁', idCard: '310115201312030377' },
|
||||
{ name: '朱思媛', idCard: '310115201407220026' },
|
||||
{ name: '李文心', idCard: '310115201312165167' },
|
||||
{ name: '刘烁恒', idCard: '310115201407273873' },
|
||||
{ name: '严潇宇', idCard: '310115201312120372' },
|
||||
{ name: '唐羿', idCard: '310107201401013958' },
|
||||
{ name: '于楚涵', idCard: '230110201408063729' },
|
||||
{ name: '肖梦晞', idCard: '340102201401081524' },
|
||||
{ name: '郑聿铭', idCard: '310114201401071633' },
|
||||
{ name: '宗柠', idCard: '310115201310094481' },
|
||||
{ name: '张子煜', idCard: '310115201401292619' },
|
||||
{ name: '刘孜宸', idCard: '430602201312280205' },
|
||||
{ name: '潘思羽', idCard: '310115201312310280' },
|
||||
],
|
||||
|
||||
// 分页配置
|
||||
needPage: false,
|
||||
pageNum: 1,
|
||||
pageSize: 40,
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 页面初始化:自动选中最后一级第一个班级(2025级(预备) -> 1班)
|
||||
this.initDefaultSelectTree()
|
||||
this.loadClassDetail()
|
||||
},
|
||||
methods: {
|
||||
// 默认选中叶子第一个班级
|
||||
initDefaultSelectTree() {
|
||||
const schoolNode = this.treeData[0]
|
||||
const targetGrade = schoolNode.children.find(g => g.title === '2025级(预备)')
|
||||
if (targetGrade && targetGrade.children.length) {
|
||||
this.selectedTreeNode = targetGrade.children[0]
|
||||
this.currentClassName = this.selectedTreeNode.title
|
||||
this.currentGrade = '2025级'
|
||||
this.currentGradeShort = '预备'
|
||||
}
|
||||
},
|
||||
|
||||
// 树节点点击切换
|
||||
treeNodeChange(node) {
|
||||
// 只响应叶子班级节点,过滤年级、学校父节点
|
||||
if (!node.children || node.children.length === 0) {
|
||||
this.currentClassName = node.title
|
||||
this.pageNum = 1
|
||||
this.loadClassDetail()
|
||||
}
|
||||
},
|
||||
|
||||
// 加载班级对应任教/学生数据
|
||||
loadClassDetail() {
|
||||
console.log('当前选中班级:', this.currentGrade + this.currentClassName)
|
||||
// 此处可替换后端接口请求
|
||||
/*
|
||||
this.$axios.get('/api/class/history', {
|
||||
params: {
|
||||
grade: this.currentGrade,
|
||||
className: this.currentClassName,
|
||||
tabType: this.activeTab
|
||||
}
|
||||
}).then(res => {
|
||||
this.teachList = res.data.teachList
|
||||
this.studentList = res.data.studentList
|
||||
this.studentTotal = res.data.studentTotal
|
||||
this.total = this.activeTab === 'teach' ? this.teachList.length : this.studentTotal
|
||||
})
|
||||
*/
|
||||
},
|
||||
tolink(item){
|
||||
this.$router.push({path:'/historySearchDetail'});
|
||||
},
|
||||
// 分页切换
|
||||
pageChange(p) {
|
||||
this.pageNum = p
|
||||
this.loadClassDetail()
|
||||
},
|
||||
sizeChange(size) {
|
||||
this.pageSize = size
|
||||
this.pageNum = 1
|
||||
this.loadClassDetail()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.class-history-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
box-sizing: border-box;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
/* 左侧树固定宽度+固定高度滚动 */
|
||||
.left-tree-box {
|
||||
width: 260px;
|
||||
border: 1px solid #e5e7eb;
|
||||
overflow-y: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 右侧整体弹性布局 */
|
||||
.right-main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* 顶部班级信息行 */
|
||||
.top-info-bar {
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
padding: 8px 0 12px;
|
||||
}
|
||||
.info-item {
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.filter-bar {
|
||||
padding: 10px 12px;
|
||||
background: #f5f7fa;
|
||||
margin: 8px 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* 核心滚动容器:自适应剩余高度,内部纵向滑动 */
|
||||
.scroll-content-box {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
/* 任教方块流式布局 */
|
||||
.teach-wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 14px;
|
||||
}
|
||||
.item-card {
|
||||
width: 160px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
.card-title {
|
||||
background: #4080ff;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
padding: 8px 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
.card-value {
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
background: #f9fafc;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
/* 学生方块布局 */
|
||||
.student-wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
.student-card {
|
||||
width: 320px;
|
||||
padding: 10px 8px;
|
||||
background: #4080ff;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/* 分页永久固定底部 */
|
||||
.page-bottom-bar {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding-top: 14px;
|
||||
gap: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,153 @@
|
||||
<template>
|
||||
<div class="student-teach-detail-wrap">
|
||||
<!-- 顶部标题栏 -->
|
||||
<div class="top-header-bar">
|
||||
<div class="left-info">
|
||||
<span class="label">当前学生:</span>
|
||||
<span class="text">{{ studentName }}</span>
|
||||
<span class="label" style="margin-left: 24px;">当前班级:</span>
|
||||
<span class="text">{{ className }}</span>
|
||||
</div>
|
||||
<Button type="primary" @click="goBack">返回上一级</Button>
|
||||
</div>
|
||||
|
||||
<!-- 时间段+学校班级栏 -->
|
||||
<div class="time-school-bar">
|
||||
<span>日期:{{ dateRange }}</span>
|
||||
<span style="margin-left: 20px;">{{ schoolName }} {{ className }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 科目教师卡片流式容器,超出纵向滚动 -->
|
||||
<div class="card-scroll-wrap">
|
||||
<div class="card-container">
|
||||
<div class="subject-card" v-for="(item, index) in subjectList" :key="index">
|
||||
<div class="card-title">{{ item.subject }}</div>
|
||||
<div class="card-teacher">{{ item.teacher }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'StudentTeachDetail',
|
||||
data() {
|
||||
return {
|
||||
// 头部信息
|
||||
studentName: '朱思媛',
|
||||
className: '预备1班',
|
||||
schoolName: '上海市进才中学北校',
|
||||
dateRange: '2025-07-11~2026-07-15',
|
||||
|
||||
// 科目+教师数据源(完全匹配截图)
|
||||
subjectList: [
|
||||
{ subject: '班主任', teacher: '伍芳芳' },
|
||||
{ subject: '副班主任', teacher: '未设置' },
|
||||
{ subject: '语文', teacher: '卫红' },
|
||||
{ subject: '数学', teacher: '伍芳芳' },
|
||||
{ subject: '英语', teacher: '俞莉玉' },
|
||||
{ subject: '体育', teacher: '郑浩淼' },
|
||||
{ subject: '美术', teacher: '蔡婷婷' },
|
||||
{ subject: '科学', teacher: '游宝玲' },
|
||||
{ subject: '劳技', teacher: '牛乐' },
|
||||
{ subject: '地理', teacher: '沈晓燕' },
|
||||
{ subject: '音乐', teacher: '李海昆' },
|
||||
|
||||
{ subject: '心理', teacher: '展望' },
|
||||
{ subject: '道德与法治', teacher: '郭雨佳' },
|
||||
{ subject: '班主任', teacher: '伍芳芳' },
|
||||
{ subject: '劳动', teacher: '牛乐' },
|
||||
{ subject: '信息科技', teacher: '张颖' },
|
||||
{ subject: '副班主任', teacher: '展望' },
|
||||
{ subject: '校本(劳动教育)', teacher: '牛乐' },
|
||||
{ subject: '体育与健康', teacher: '郑浩淼' },
|
||||
{ subject: '二外', teacher: '季思飞' },
|
||||
{ subject: '校本(心理+二外)', teacher: '数字化中心09' }
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 返回上一页
|
||||
goBack() {
|
||||
this.$router.go(-1)
|
||||
// 也可指定路由跳转
|
||||
// this.$router.push('/对应路由地址')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.student-teach-detail-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
/* 顶部头部行 */
|
||||
.top-header-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.left-info {
|
||||
font-size: 22px;
|
||||
}
|
||||
.label {
|
||||
color: #333;
|
||||
}
|
||||
.text {
|
||||
color: #2d7ff9;
|
||||
}
|
||||
|
||||
/* 日期学校栏 */
|
||||
.time-school-bar {
|
||||
padding: 12px 16px;
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
margin-bottom: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 卡片滚动容器:占剩余高度,内容溢出纵向滚动 */
|
||||
.card-scroll-wrap {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.card-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
/* 单个科目卡片样式 */
|
||||
.subject-card {
|
||||
width: 162px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.card-title {
|
||||
background-color: #4080ff;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
padding: 9px 4px;
|
||||
font-size: 15px;
|
||||
}
|
||||
.card-teacher {
|
||||
text-align: center;
|
||||
padding: 11px 4px;
|
||||
background-color: #f9fafc;
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,570 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<div class="btn-top-wrap">
|
||||
<Button type="primary" @click="openAddModal">添加学年学期</Button>
|
||||
</div>
|
||||
<!-- 表格 -->
|
||||
<Table
|
||||
border
|
||||
:columns="tableColumns"
|
||||
:data="yeartermlist"
|
||||
stripe
|
||||
:height="useTableHeight()+112"
|
||||
class="term-table"
|
||||
/>
|
||||
<!-- 新增弹窗 -->
|
||||
<Modal v-model="addModalVisible" title="添加学年学期" width="720" class="modalform">
|
||||
<Form
|
||||
:model="addForm"
|
||||
ref="addFormRef"
|
||||
:rules="formRules"
|
||||
label-width="120px"
|
||||
class="modal-form"
|
||||
>
|
||||
<div class="form-block-title">学年设置</div>
|
||||
<FormItem label="新学年">
|
||||
<Input disabled :value="addForm.year + '学年'" />
|
||||
</FormItem>
|
||||
<Row gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="开始日期" prop="yearStartDate">
|
||||
<DatePicker
|
||||
disabled
|
||||
:value="strToDate(addForm.yearStartDate)"
|
||||
format="yyyy-MM-dd"
|
||||
placeholder="请选择日期"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="结束日期" prop="yearEndDate">
|
||||
<DatePicker
|
||||
:value="strToDate(addForm.yearEndDate)"
|
||||
@on-change="(date) => addForm.yearEndDate = dateToStr(date)"
|
||||
format="yyyy-MM-dd"
|
||||
placeholder="请选择日期"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<div class="form-block-title">学期设置</div>
|
||||
<FormItem label="升学日期" prop="upgradeDate">
|
||||
<DatePicker
|
||||
:value="strToDate(addForm.upgradeDate)"
|
||||
@on-change="(date) => addForm.upgradeDate = dateToStr(date)"
|
||||
format="yyyy-MM-dd"
|
||||
placeholder="请选择日期"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
<div class="form-block-title">第一学期设置</div>
|
||||
<Row gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="开始日期" prop="firstTermStartDate">
|
||||
<DatePicker
|
||||
type="date"
|
||||
:value="strToDate(addForm.firstTermStartDate)"
|
||||
@on-change="(date) => addForm.firstTermStartDate = dateToStr(date)"
|
||||
format="yyyy-MM-dd"
|
||||
placeholder="请选择日期"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="结束日期" prop="firstTermEndDate">
|
||||
<DatePicker
|
||||
type="date"
|
||||
:value="strToDate(addForm.firstTermEndDate)"
|
||||
@on-change="(date) => addForm.firstTermEndDate = dateToStr(date)"
|
||||
format="yyyy-MM-dd"
|
||||
placeholder="请选择日期"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<div class="form-block-title">第二学期设置</div>
|
||||
<Row gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="开始日期" prop="secondTermStartDate">
|
||||
<DatePicker
|
||||
:value="strToDate(addForm.secondTermStartDate)"
|
||||
@on-change="(date) => addForm.secondTermStartDate = dateToStr(date)"
|
||||
format="yyyy-MM-dd"
|
||||
placeholder="请选择日期"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="结束日期" prop="secondTermEndDate">
|
||||
<DatePicker
|
||||
:value="strToDate(addForm.secondTermEndDate)"
|
||||
@on-change="(date) => addForm.secondTermEndDate = dateToStr(date)"
|
||||
format="yyyy-MM-dd"
|
||||
placeholder="请选择日期"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
<div slot="footer" class="modal-footer">
|
||||
<Button @click="addModalVisible = false">取消</Button>
|
||||
<Button type="primary" @click="submitAdd">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<!-- 编辑弹窗 -->
|
||||
<Modal v-model="editModalVisible" title="修改学年学期" width="720" class="modalform">
|
||||
<Form
|
||||
:model="editForm"
|
||||
ref="editFormRef"
|
||||
:rules="formRules"
|
||||
label-width="120px"
|
||||
class="modal-form"
|
||||
>
|
||||
<div class="form-block-title">学年设置</div>
|
||||
<FormItem label="新学年">
|
||||
<Input disabled :value="editForm.year + '学年'" />
|
||||
</FormItem>
|
||||
<Row gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="开始日期" prop="yearStartDate">
|
||||
<DatePicker
|
||||
disabled
|
||||
:value="strToDate(editForm.yearStartDate)"
|
||||
format="yyyy-MM-dd"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="结束日期" prop="yearEndDate">
|
||||
<DatePicker
|
||||
:value="strToDate(editForm.yearEndDate)"
|
||||
@on-change="(date) => editForm.yearEndDate = dateToStr(date)"
|
||||
format="yyyy-MM-dd"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<div class="form-block-title">学期设置</div>
|
||||
<FormItem label="升学日期" prop="upgradeDate">
|
||||
<DatePicker
|
||||
:value="strToDate(editForm.upgradeDate)"
|
||||
@on-change="(date) => editForm.upgradeDate = dateToStr(date)"
|
||||
format="yyyy-MM-dd"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
<div class="form-block-title">第一学期设置</div>
|
||||
<Row gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="开始日期" prop="firstTermStartDate">
|
||||
<DatePicker
|
||||
:value="strToDate(editForm.firstTermStartDate)"
|
||||
@on-change="(date) => editForm.firstTermStartDate = dateToStr(date)"
|
||||
format="yyyy-MM-dd"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="结束日期" prop="firstTermEndDate">
|
||||
<DatePicker
|
||||
:value="strToDate(editForm.firstTermEndDate)"
|
||||
@on-change="(date) => editForm.firstTermEndDate = dateToStr(date)"
|
||||
format="yyyy-MM-dd"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<div class="form-block-title">第二学期设置</div>
|
||||
<Row gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="开始日期" prop="secondTermStartDate">
|
||||
<DatePicker
|
||||
:value="strToDate(editForm.secondTermStartDate)"
|
||||
@on-change="(date) => editForm.secondTermStartDate = dateToStr(date)"
|
||||
format="yyyy-MM-dd"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="结束日期" prop="secondTermEndDate">
|
||||
<DatePicker
|
||||
:value="strToDate(editForm.secondTermEndDate)"
|
||||
@on-change="(date) => editForm.secondTermEndDate = dateToStr(date)"
|
||||
format="yyyy-MM-dd"
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
<div slot="footer" class="modal-footer">
|
||||
<Button @click="editModalVisible = false">取消</Button>
|
||||
<Button type="primary" @click="submitEdit">保存</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: "AcademicYearTerm",
|
||||
data() {
|
||||
return {
|
||||
tableColumns: [
|
||||
{
|
||||
title: "学年",
|
||||
key: "year",
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
const row = params.row;
|
||||
const text = row.nowYear ? `${row.year}学年(当前学年)` : `${row.year}学年`;
|
||||
return h("div", { style: "line-height: 56px" }, text);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "学年开始日期",
|
||||
key: "yearStartDate",
|
||||
align: "center",
|
||||
render: (h, params) => h("div", { style: "line-height: 56px" }, params.row.yearStartDate)
|
||||
},
|
||||
{
|
||||
title: "学年结束日期",
|
||||
key: "yearEndDate",
|
||||
align: "center",
|
||||
render: (h, params) => h("div", { style: "line-height: 56px" }, params.row.yearEndDate)
|
||||
},
|
||||
{
|
||||
title: "学期名称",
|
||||
key: "termName",
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h("div", "第一学期"),
|
||||
h("div", { style: "margin-top: 8px" }, "第二学期")
|
||||
]);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "起始日期",
|
||||
key: "startDate",
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h("div", params.row.firstTermStartDate),
|
||||
h("div", { style: "margin-top: 8px" }, params.row.secondTermStartDate)
|
||||
]);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "截止日期",
|
||||
key: "endDate",
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
return h("div", [
|
||||
h("div", params.row.firstTermEndDate),
|
||||
h("div", { style: "margin-top: 8px" }, params.row.secondTermEndDate)
|
||||
]);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
width: 90,
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
return h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
icon: "ios-create",
|
||||
shape: "circle"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.openEditModal(params.row);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
],
|
||||
yeartermlist: [],
|
||||
addModalVisible: false,
|
||||
addForm: {
|
||||
year: new Date().getFullYear(),
|
||||
yearStartDate: new Date().getFullYear() + "-07-15",
|
||||
yearEndDate: "",
|
||||
upgradeDate: "",
|
||||
firstTermStartDate: "",
|
||||
firstTermEndDate: "",
|
||||
secondTermStartDate: "",
|
||||
secondTermEndDate: ""
|
||||
},
|
||||
editModalVisible: false,
|
||||
editForm: {
|
||||
id: null,
|
||||
year: "",
|
||||
yearStartDate: "",
|
||||
yearEndDate: "",
|
||||
upgradeDate: "",
|
||||
firstTermStartDate: "",
|
||||
firstTermEndDate: "",
|
||||
secondTermStartDate: "",
|
||||
secondTermEndDate: ""
|
||||
},
|
||||
// 修复formRules语法错误
|
||||
formRules: {
|
||||
year: [{ required: true, message: "请填写学年", trigger: "blur" }],
|
||||
yearStartDate: [{ required: true, message: "请选择学年开始日期", trigger: "change" }],
|
||||
yearEndDate: [{ required: true, message: "请选择学年结束日期", trigger: "change" }],
|
||||
upgradeDate: [{ required: true, message: "请选择升学日期", trigger: "change" }],
|
||||
firstTermStartDate: [{ required: true, message: "请选择第一学期开始日期", trigger: "change" }],
|
||||
firstTermEndDate: [{ required: true, message: "请选择第一学期结束日期", trigger: "change" }],
|
||||
secondTermStartDate: [{ required: true, message: "请选择第二学期开始日期", trigger: "change" }],
|
||||
secondTermEndDate: [{ required: true, message: "请选择第二学期结束日期", trigger: "change" }]
|
||||
}
|
||||
};
|
||||
},
|
||||
mixins: [self_viewport],
|
||||
mounted() {
|
||||
this.getschsystemlist();
|
||||
},
|
||||
methods: {
|
||||
// 日期转换:Date对象 → yyyy-MM-dd 标准字符串
|
||||
dateToStr(date) {
|
||||
if (!date) return "";
|
||||
const y = new Date(date).getFullYear();
|
||||
const m = String(new Date(date).getMonth() + 1).padStart(2, "0");
|
||||
const d = String(new Date(date).getDate()).padStart(2, "0");
|
||||
return `${y}-${m}-${d}`;
|
||||
},
|
||||
// 日期转换:字符串/后端ISO时间 → Date对象 给DatePicker回填
|
||||
strToDate(inputStr) {
|
||||
if (!inputStr) return null;
|
||||
// 处理后端带T的ISO格式
|
||||
let str = inputStr.includes("T") ? inputStr.split("T")[0] : inputStr;
|
||||
const arr = str.split("-");
|
||||
if (arr.length !== 3) return null;
|
||||
const year = arr[0];
|
||||
const month = arr[1].padStart(2, "0");
|
||||
const day = arr[2].padStart(2, "0");
|
||||
const standard = `${year}-${month}-${day}`;
|
||||
const date = new Date(standard);
|
||||
// 非法日期返回空
|
||||
return isNaN(date.getTime()) ? null : date;
|
||||
},
|
||||
//获取学校绑定学制列表
|
||||
getschsystemlist() {
|
||||
const _this = this;
|
||||
var item = {};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getyeartermlist, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.yeartermlist = resp.data;
|
||||
} else {
|
||||
_this.yeartermlist = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
openAddModal() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.addFormRef?.resetFields();
|
||||
});
|
||||
const curYear = new Date().getFullYear();
|
||||
this.addForm = {
|
||||
year: curYear,
|
||||
yearStartDate: curYear + "-07-15",
|
||||
yearEndDate: "",
|
||||
upgradeDate: "",
|
||||
firstTermStartDate: "",
|
||||
firstTermEndDate: "",
|
||||
secondTermStartDate: "",
|
||||
secondTermEndDate: ""
|
||||
};
|
||||
this.addModalVisible = true;
|
||||
},
|
||||
submitAdd() {
|
||||
this.$refs.addFormRef.validate(valid => {
|
||||
if (!valid) return;
|
||||
const form = this.addForm;
|
||||
// 1、学年数字校验(对齐后端 @Min(2000) @Positive)
|
||||
const yearNum = Number(form.year);
|
||||
if (!Number.isInteger(yearNum) || yearNum <= 0) {
|
||||
this.$Message.error("学年必须为正整数");
|
||||
return;
|
||||
}
|
||||
if (yearNum < 2000) {
|
||||
this.$Message.error("学年不能小于2000");
|
||||
return;
|
||||
}
|
||||
// 快速转日期
|
||||
const getDate = (s) => new Date(s);
|
||||
const ys = getDate(form.yearStartDate);
|
||||
const ye = getDate(form.yearEndDate);
|
||||
const t1s = getDate(form.firstTermStartDate);
|
||||
const t1e = getDate(form.firstTermEndDate);
|
||||
const t2s = getDate(form.secondTermStartDate);
|
||||
const t2e = getDate(form.secondTermEndDate);
|
||||
const up = getDate(form.upgradeDate);
|
||||
|
||||
if (ys > ye) {
|
||||
this.$Message.error("学年开始日期不能晚于学年结束日期");
|
||||
return;
|
||||
}
|
||||
if (t1s > t1e) {
|
||||
this.$Message.error("第一学期开始日期不能晚于第一学期结束日期");
|
||||
return;
|
||||
}
|
||||
if (t2s > t2e) {
|
||||
this.$Message.error("第二学期开始日期不能晚于第二学期结束日期");
|
||||
return;
|
||||
}
|
||||
if (t1e > t2s) {
|
||||
this.$Message.error("第一学期结束日期不能晚于第二学期开始日期");
|
||||
return;
|
||||
}
|
||||
if (up < ye) {
|
||||
this.$Message.error("毕业日期不能早于学年结束日期");
|
||||
return;
|
||||
}
|
||||
// 组装提交参数,year传数字,日期传标准yyyy-MM-dd字符串
|
||||
const submitData = {
|
||||
year: yearNum,
|
||||
yearStartDate: form.yearStartDate,
|
||||
yearEndDate: form.yearEndDate,
|
||||
firstTermStartDate: form.firstTermStartDate,
|
||||
firstTermEndDate: form.firstTermEndDate,
|
||||
secondTermStartDate: form.secondTermStartDate,
|
||||
secondTermEndDate: form.secondTermEndDate,
|
||||
upgradeDate: form.upgradeDate
|
||||
};
|
||||
const url = APIConfig.BschClassSystem.yeartermadd;
|
||||
this.$api.post(url, JSON.stringify(submitData), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("添加成功!");
|
||||
this.addModalVisible = false;
|
||||
this.getschsystemlist();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
openEditModal(row) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.editFormRef?.resetFields();
|
||||
});
|
||||
this.editForm = {
|
||||
id: row.id,
|
||||
year: row.year,
|
||||
yearStartDate: row.yearStartDate,
|
||||
yearEndDate: row.yearEndDate,
|
||||
upgradeDate: row.upgradeDate,
|
||||
firstTermStartDate: row.firstTermStartDate,
|
||||
firstTermEndDate: row.firstTermEndDate,
|
||||
secondTermStartDate: row.secondTermStartDate,
|
||||
secondTermEndDate: row.secondTermEndDate
|
||||
};
|
||||
this.editModalVisible = true;
|
||||
},
|
||||
submitEdit() {
|
||||
this.$refs.editFormRef.validate(valid => {
|
||||
if (!valid) return;
|
||||
const form = this.editForm;
|
||||
console.log(JSON.stringify(form));
|
||||
// 学年数字校验
|
||||
const yearNum = Number(form.year);
|
||||
if (!Number.isInteger(yearNum) || yearNum <= 0) {
|
||||
this.$Message.error("学年必须为正整数");
|
||||
return;
|
||||
}
|
||||
if (yearNum < 2000) {
|
||||
this.$Message.error("学年不能小于2000");
|
||||
return;
|
||||
}
|
||||
const getDate = (s) => new Date(s);
|
||||
const ys = getDate(form.yearStartDate);
|
||||
const ye = getDate(form.yearEndDate);
|
||||
const t1s = getDate(form.firstTermStartDate);
|
||||
const t1e = getDate(form.firstTermEndDate);
|
||||
const t2s = getDate(form.secondTermStartDate);
|
||||
const t2e = getDate(form.secondTermEndDate);
|
||||
const up = getDate(form.upgradeDate);
|
||||
|
||||
if (ys > ye) {
|
||||
this.$Message.error("学年开始日期不能晚于学年结束日期");
|
||||
return;
|
||||
}
|
||||
if (t1s > t1e) {
|
||||
this.$Message.error("第一学期开始日期不能晚于第一学期结束日期");
|
||||
return;
|
||||
}
|
||||
if (t2s > t2e) {
|
||||
this.$Message.error("第二学期开始日期不能晚于第二学期结束日期");
|
||||
return;
|
||||
}
|
||||
if (t1e > t2s) {
|
||||
this.$Message.error("第一学期结束日期不能晚于第二学期开始日期");
|
||||
return;
|
||||
}
|
||||
if (up < ye) {
|
||||
this.$Message.error("毕业日期不能早于学年结束日期");
|
||||
return;
|
||||
}
|
||||
// 编辑提交参数
|
||||
const submitData = {
|
||||
id: form.id,
|
||||
year: yearNum,
|
||||
yearStartDate: form.yearStartDate,
|
||||
yearEndDate: form.yearEndDate,
|
||||
firstTermStartDate: form.firstTermStartDate,
|
||||
firstTermEndDate: form.firstTermEndDate,
|
||||
secondTermStartDate: form.secondTermStartDate,
|
||||
secondTermEndDate: form.secondTermEndDate,
|
||||
upgradeDate: form.upgradeDate
|
||||
};
|
||||
const url = APIConfig.BschClassSystem.yeartermedit;
|
||||
this.$api.post(url, JSON.stringify(submitData), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("修改成功!");
|
||||
this.editModalVisible = false;
|
||||
this.getschsystemlist();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.page-container {
|
||||
padding:0 16px;
|
||||
background: #fff;
|
||||
}
|
||||
.page-title {
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
margin: 0 0 12px;
|
||||
}
|
||||
.btn-top-wrap {
|
||||
background: #f7f8fa;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
/* margin: 10px 0 15px; */
|
||||
}
|
||||
.term-table /deep/ .ivu-table-row td {
|
||||
padding: 6px 0;
|
||||
}
|
||||
.form-block-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin: 10px 0 10px;
|
||||
padding-left: 6px;
|
||||
border-left: 4px solid #2d8cf0;
|
||||
}
|
||||
.modal-footer {
|
||||
text-align: right;
|
||||
}
|
||||
.modalform /deep/ .ivu-modal-body{
|
||||
padding:10px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,679 @@
|
||||
<template>
|
||||
<div class="page-wrap">
|
||||
<Tabs v-model="activeTab">
|
||||
<TabPane label="校区管理" name="campus"></TabPane>
|
||||
<TabPane label="系部管理" name="dept"></TabPane>
|
||||
<TabPane label="专业管理" name="major"></TabPane>
|
||||
</Tabs>
|
||||
|
||||
<!-- ====================== 校区管理【hover显示删除】 ====================== -->
|
||||
<div v-if="activeTab === 'campus'" class="tab-panel">
|
||||
<div class="btn-container">
|
||||
<draggable
|
||||
v-model="campuslist"
|
||||
animation="150"
|
||||
ghost-class="drag-ghost"
|
||||
class="drag-box"
|
||||
:options="{ group: 'people' }"
|
||||
@start="drag = true"
|
||||
@end="drag = false"
|
||||
:move="getdata1"
|
||||
@update="datadragEnd1"
|
||||
>
|
||||
<div
|
||||
v-for="(item, index) in campuslist"
|
||||
:key="index"
|
||||
class="tag-wrap"
|
||||
@dblclick="openEditModal('campus', index)"
|
||||
>
|
||||
<div class="tag-btn">{{ item.name }}</div>
|
||||
<span class="close-btn" @click.stop="delCampus(index)">×</span>
|
||||
</div>
|
||||
</draggable>
|
||||
<Button icon="ios-add" size="large" class="add-btn" @click="openAddModal('campus')">添加校区</Button>
|
||||
</div>
|
||||
<div class="tip-info">
|
||||
<Icon type="ios-information-circle-outline"></Icon>
|
||||
双击编辑,拖动排序
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ====================== 系部管理【hover显示删除】 ====================== -->
|
||||
<div v-if="activeTab === 'dept'" class="tab-panel">
|
||||
<div class="btn-container">
|
||||
<draggable
|
||||
v-model="divisionlist"
|
||||
animation="150"
|
||||
ghost-class="drag-ghost"
|
||||
class="drag-box"
|
||||
:options="{ group: 'people' }"
|
||||
@start="drag = true"
|
||||
@end="drag = false"
|
||||
:move="getdata2"
|
||||
@update="datadragEnd2"
|
||||
>
|
||||
<div
|
||||
v-for="(item, index) in divisionlist"
|
||||
:key="index"
|
||||
class="tag-wrap"
|
||||
@dblclick="openEditModal('dept', index)"
|
||||
>
|
||||
<div class="tag-btn">{{ item.name }}</div>
|
||||
<span class="close-btn" @click.stop="delDept(index)">×</span>
|
||||
</div>
|
||||
</draggable>
|
||||
<Button icon="ios-add" size="large" class="add-btn" @click="openAddModal('dept')">添加系部</Button>
|
||||
</div>
|
||||
<div class="tip-info">
|
||||
<Icon type="ios-information-circle-outline"></Icon>
|
||||
双击编辑,拖动排序
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ====================== 专业管理【修复拖拽失效】 ====================== -->
|
||||
<div v-if="activeTab === 'major'" class="tab-panel major-adapt-wrap">
|
||||
<div class="major-top-bar">
|
||||
<Button type="primary" icon="ios-add" @click="openMajorAdd">添加专业</Button>
|
||||
<div class="search-box">
|
||||
<i-Input
|
||||
v-model="majorKeyword"
|
||||
placeholder="输入代码或名称搜索"
|
||||
@keyup.enter="searchMajor"
|
||||
>
|
||||
<Icon slot="suffix" type="ios-search" @click="searchMajor" style="cursor:pointer;"></Icon>
|
||||
</i-Input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-scroll-box" ref="tableBoxRef">
|
||||
<Table
|
||||
border
|
||||
stripe
|
||||
:columns="majorColumns"
|
||||
:data="majorTableData"
|
||||
class="major-table"
|
||||
ref="tableRef"
|
||||
></Table>
|
||||
</div>
|
||||
|
||||
<!-- <div class="pagination-fixed-bottom">
|
||||
<span class="total-desc">共 {{ majorTotal }} 条</span>
|
||||
<Page
|
||||
:current.sync="majorPageNum"
|
||||
:total="majorTotal"
|
||||
:page-size="majorPageSize"
|
||||
:page-size-opts="[10,20,50]"
|
||||
show-sizer
|
||||
@on-change="majorPageChange"
|
||||
@on-page-size-change="majorSizeChange"
|
||||
></Page>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<!-- 校区/系部 新增编辑弹窗 -->
|
||||
<Modal v-model="modalVisible" :title="modalTitle" width="420">
|
||||
<Form ref="formRef" :model="formData" :rules="formRule" label-width="90">
|
||||
<FormItem label="校区名称" v-if="modalType === 'campus'" prop="name">
|
||||
<Input v-model="formData.name" placeholder="请输入校区名称" />
|
||||
</FormItem>
|
||||
<FormItem label="系部名称" v-if="modalType === 'dept'" prop="name">
|
||||
<Input v-model="formData.name" placeholder="请输入系部名称" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="modalVisible = false" style="margin-right: 10px">取消</Button>
|
||||
<Button type="primary" @click="submitModal">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 专业新增编辑弹窗 -->
|
||||
<Modal v-model="majorModalVisible" :title="majorModalTitle" width="460">
|
||||
<Form ref="majorFormRef" :model="majorForm" :rules="majorFormRule" label-width="90">
|
||||
<FormItem label="专业代码">
|
||||
<Input v-model="majorForm.code" placeholder="请输入专业代码" />
|
||||
</FormItem>
|
||||
<FormItem label="专业名称" prop="name">
|
||||
<Input v-model="majorForm.name" placeholder="请输入专业名称" />
|
||||
</FormItem>
|
||||
<FormItem label="学制" prop="schsystemLeng">
|
||||
<Input v-model="majorForm.schsystemLeng" type="number" placeholder="请输入学制" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="majorModalVisible = false" style="margin-right: 10px">取消</Button>
|
||||
<Button type="primary" @click="submitMajorModal">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
import Sortable from 'sortablejs'
|
||||
export default {
|
||||
name: 'SchoolSetting',
|
||||
components: { draggable },
|
||||
data() {
|
||||
return {
|
||||
activeTab: 'campus',
|
||||
campuslist: [],
|
||||
divisionlist: [],
|
||||
|
||||
modalVisible: false,
|
||||
modalType: '',
|
||||
modalTitle: '',
|
||||
editIndex: null,
|
||||
formData: { id:0,name:'' },
|
||||
formRule: {
|
||||
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }]
|
||||
},
|
||||
|
||||
majorKeyword: '',
|
||||
majorPageNum: 1,
|
||||
majorPageSize: 10,
|
||||
majorTotal: 22,
|
||||
majorColumns: [
|
||||
{
|
||||
title: '序号',
|
||||
key: '_index',
|
||||
align: 'center',
|
||||
width: 70,
|
||||
render: (h, params) => h('span', params.index + 1)
|
||||
},
|
||||
{ title: 'ID', key: 'id', align: 'center' },
|
||||
{ title: '专业代码', key: 'code', align: 'center' },
|
||||
{ title: '专业名称', key: 'name', align: 'center' },
|
||||
{ title: '学制', key: 'schsystemLeng', align: 'center' },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
width: 170,
|
||||
render: (h, params) => {
|
||||
return h('div', { style: 'display:flex;gap:8px;justify-content:center;align-items:center' }, [
|
||||
h('Button', {
|
||||
props: { type: 'text', icon: 'ios-create', size: 'small' },
|
||||
on: { click: () => this.openMajorEdit(params.index) }
|
||||
}),
|
||||
h('Button', {
|
||||
props: { type: 'text', icon: 'ios-trash', size: 'small' },
|
||||
on: { click: () => this.delMajor(params.index) }
|
||||
}),
|
||||
// 拖拽把手class固定为 drag-handle
|
||||
h('Icon', {
|
||||
props: { type: 'ios-move', size: 18, title: '拖动排序' },
|
||||
class: 'drag-handle drag-icon'
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
],
|
||||
majorTableData: [],
|
||||
majorModalVisible: false,
|
||||
majorModalTitle: '',
|
||||
majorEditIndex: null,
|
||||
majorForm: { code: '', name: '', schsystemLeng: '' },
|
||||
majorFormRule: {
|
||||
code: [{ required: true, message: '专业代码不能为空', trigger: 'blur' }],
|
||||
name: [{ required: true, message: '专业名称不能为空', trigger: 'blur' }],
|
||||
schsystemLeng: [{ required: true, message: '学制不能为空', trigger: 'blur' }]
|
||||
},
|
||||
tableDrag: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 切换标签页重新初始化拖拽
|
||||
activeTab(val) {
|
||||
if (val === 'major') {
|
||||
this.$nextTick(() => this.initTableDrag())
|
||||
this.getmajorslist();
|
||||
} else if(val === 'campus') {
|
||||
if (this.tableDrag) this.tableDrag.destroy();
|
||||
this.getcampuslist();
|
||||
}else{
|
||||
if (this.tableDrag) this.tableDrag.destroy();
|
||||
this.getdivisionlist();
|
||||
}
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.getcampuslist();
|
||||
},
|
||||
mounted() {
|
||||
// 延时确保表格完全渲染完毕再初始化
|
||||
setTimeout(() => {
|
||||
if (this.activeTab === 'major') {
|
||||
this.initTableDrag()
|
||||
}
|
||||
}, 120)
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.tableDrag) this.tableDrag.destroy()
|
||||
},
|
||||
methods: {
|
||||
//获取学校分校列表
|
||||
getcampuslist() {
|
||||
const _this = this;
|
||||
var item = {};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getcampuslist, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.campuslist = resp.data;
|
||||
} else {
|
||||
_this.campuslist = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取系部列表
|
||||
getdivisionlist() {
|
||||
const _this = this;
|
||||
var item = {};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getdivisionlist, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.divisionlist = resp.data;
|
||||
} else {
|
||||
_this.divisionlist = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取专业列表
|
||||
getmajorslist() {
|
||||
const _this = this;
|
||||
var item = {
|
||||
keyword:_this.majorKeyword
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getmajorslist, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.majorTableData = resp.data;
|
||||
} else {
|
||||
_this.majorTableData = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
//校区拖动前
|
||||
getdata1 (evt) {
|
||||
//console.log(evt.draggedContext.element)
|
||||
},
|
||||
|
||||
//校区拖动后
|
||||
datadragEnd1 (evt) {
|
||||
var _this=this;
|
||||
//console.log('拖动后的索引 :' + evt.newIndex);
|
||||
//console.log('拖动前的索引 :' + evt.oldIndex);
|
||||
var ids=[],orders=[];
|
||||
_this.campuslist.forEach(element => {
|
||||
ids.push(element.id);
|
||||
});
|
||||
var url=APIConfig.BschClassSystem.campussort;
|
||||
_this.$api.post(url,JSON.stringify(ids),(resp)=>{
|
||||
_this.$Message.info('拖动排序成功!');
|
||||
_this.getcampuslist();
|
||||
});
|
||||
},
|
||||
//系部拖动前
|
||||
getdata2 (evt) {
|
||||
//console.log(evt.draggedContext.element)
|
||||
},
|
||||
|
||||
//系部拖动后
|
||||
datadragEnd2 (evt) {
|
||||
var _this=this;
|
||||
//console.log('拖动后的索引 :' + evt.newIndex);
|
||||
//console.log('拖动前的索引 :' + evt.oldIndex);
|
||||
var ids=[],orders=[];
|
||||
_this.divisionlist.forEach(element => {
|
||||
ids.push(element.id);
|
||||
});
|
||||
var url=APIConfig.BschClassSystem.divisionsort;
|
||||
_this.$api.post(url,JSON.stringify(ids),(resp)=>{
|
||||
_this.$Message.info('拖动排序成功!');
|
||||
_this.getdivisionlist();
|
||||
});
|
||||
},
|
||||
// 表格拖拽初始化【修复关键点】
|
||||
initTableDrag() {
|
||||
if (this.tableDrag) {
|
||||
this.tableDrag.destroy()
|
||||
this.tableDrag = null
|
||||
}
|
||||
const tableEl = this.$refs.tableRef?.$el
|
||||
if (!tableEl) return
|
||||
const tbody = tableEl.querySelector('tbody')
|
||||
if (!tbody) return
|
||||
|
||||
this.tableDrag = new Sortable(tbody, {
|
||||
animation: 0, // 关闭Sortable自带DOM位移动画
|
||||
swap: false,
|
||||
handle: '.drag-handle',
|
||||
ghostClass: 'table-drag-ghost',
|
||||
preventOnFilter: true,
|
||||
// 关键:Sortable只计算下标,不改动页面DOM结构
|
||||
forceAutoScroll: true,
|
||||
onEnd: (evt) => {
|
||||
const oldIndex = evt.oldIndex
|
||||
const newIndex = evt.newIndex
|
||||
if (oldIndex === newIndex) return
|
||||
|
||||
// ========== 关键 1:撤销 Sortable 的 DOM 操作 ==========
|
||||
const tbody = evt.to
|
||||
const rows = Array.from(tbody.querySelectorAll('tr'))
|
||||
// 计算元素原来应该插回的位置
|
||||
const refIndex = oldIndex < newIndex ? oldIndex : oldIndex + 1
|
||||
const refNode = rows[refIndex]
|
||||
if (refNode) {
|
||||
tbody.insertBefore(evt.item, refNode)
|
||||
} else {
|
||||
tbody.appendChild(evt.item)
|
||||
}
|
||||
// ========== 关键 2:用 splice 移动数组元素(不是交换!) ==========
|
||||
const movedItem = this.majorTableData[oldIndex]
|
||||
this.majorTableData.splice(oldIndex, 1)
|
||||
this.majorTableData.splice(newIndex, 0, movedItem)
|
||||
|
||||
// ========== 后端排序接口 ==========
|
||||
const ids = this.majorTableData.map(item => item.id)
|
||||
const url = APIConfig.BschClassSystem.majorssort
|
||||
this.$api.post(url, JSON.stringify(ids), (resp) => {
|
||||
this.$Message.info('拖动排序成功!');
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// ========== 校区删除 ==========
|
||||
delCampus(index) {
|
||||
this.$Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定删除该校区?',
|
||||
onOk: () => {
|
||||
var url=APIConfig.BschClassSystem.campusdelete+this.campuslist[index].id;
|
||||
this.$api.post(url,{},(resp)=>{
|
||||
this.$Message.success('删除成功!');
|
||||
this.getcampuslist();
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
// ========== 系部删除 ==========
|
||||
delDept(index) {
|
||||
this.$Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定删除该系部?',
|
||||
onOk: () => {
|
||||
var url=APIConfig.BschClassSystem.divisiondelete+this.divisionlist[index].id;
|
||||
this.$api.post(url,{},(resp)=>{
|
||||
this.$Message.success('删除成功!');
|
||||
this.getdivisionlist();
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// ========== 校区/系部 弹窗逻辑 ==========
|
||||
openAddModal(type) {
|
||||
this.modalType = type;
|
||||
this.editIndex = null;
|
||||
this.formData.id = 0;
|
||||
this.formData.name = '';
|
||||
this.modalTitle = type === 'campus' ? '新增校区' : '新增系部';
|
||||
this.modalVisible = true;
|
||||
this.$nextTick(() => this.$refs.formRef.clearValidate());
|
||||
},
|
||||
openEditModal(type, index) {
|
||||
this.modalType = type;
|
||||
this.editIndex = index;
|
||||
const list = type === 'campus' ? this.campuslist : this.divisionlist;
|
||||
this.formData = list[index];
|
||||
this.modalTitle = type === 'campus' ? '校区信息' : '系部信息';
|
||||
this.modalVisible = true;
|
||||
this.$nextTick(() => this.$refs.formRef.clearValidate());
|
||||
},
|
||||
submitModal() {
|
||||
this.$refs.formRef.validate(valid => {
|
||||
if (!valid) return
|
||||
const name = this.formData.name.trim()
|
||||
const list = this.modalType === 'campus' ? this.campuslist : this.divisionlist;
|
||||
const hasRepeat = list.some((item, i) => item.name === name && i !== this.editIndex);
|
||||
if (hasRepeat) {
|
||||
this.$Message.error('名称已存在,不能重复')
|
||||
return
|
||||
}
|
||||
if (this.editIndex === null) {
|
||||
const submitData = {
|
||||
name: name
|
||||
};
|
||||
const url =this.modalType === 'campus' ? APIConfig.BschClassSystem.campussave:APIConfig.BschClassSystem.divisionsave;
|
||||
this.$api.post(url, JSON.stringify(submitData), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("添加成功!");
|
||||
this.modalType === 'campus' ? this.getcampuslist() : this.getdivisionlist();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const submitData = {
|
||||
id:this.formData.id,
|
||||
sort:this.formData.sort,
|
||||
name: name
|
||||
};
|
||||
const url =this.modalType === 'campus' ? APIConfig.BschClassSystem.campussave:APIConfig.BschClassSystem.divisionsave;
|
||||
this.$api.post(url, JSON.stringify(submitData), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("修改成功!");
|
||||
this.modalType === 'campus' ? this.getcampuslist() : this.getdivisionlist();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.modalVisible = false
|
||||
})
|
||||
},
|
||||
|
||||
// ========== 专业管理 ==========
|
||||
openMajorAdd() {
|
||||
this.majorEditIndex = null
|
||||
this.majorForm = { code: '', name: '', schsystemLeng: '' }
|
||||
this.majorModalTitle = '新增专业'
|
||||
this.majorModalVisible = true
|
||||
this.$nextTick(() => this.$refs.majorFormRef.clearValidate())
|
||||
},
|
||||
openMajorEdit(index) {
|
||||
this.majorEditIndex = index
|
||||
const row = this.majorTableData[index];
|
||||
row.schsystemLeng=this.majorTableData[index].schsystemLeng+'';
|
||||
this.majorForm = { ...row }
|
||||
this.$nextTick(() => this.$refs.majorFormRef.clearValidate())
|
||||
this.majorModalTitle = '编辑专业'
|
||||
this.majorModalVisible = true
|
||||
},
|
||||
submitMajorModal() {
|
||||
this.$refs.majorFormRef.validate(valid => {
|
||||
if (!valid) return
|
||||
if (this.majorEditIndex === null) {
|
||||
const submitData =this.majorForm;
|
||||
const url = APIConfig.BschClassSystem.majorssave;
|
||||
this.$api.post(url, JSON.stringify(submitData), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("新增专业成功!");
|
||||
this.getmajorslist();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const submitData =this.majorForm;
|
||||
const url = APIConfig.BschClassSystem.majorssave;
|
||||
this.$api.post(url, JSON.stringify(submitData), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("编辑专业成功!");
|
||||
this.getmajorslist();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.majorModalVisible = false
|
||||
this.$nextTick(() => this.initTableDrag())
|
||||
})
|
||||
},
|
||||
delMajor(index) {
|
||||
this.$Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定删除该专业?',
|
||||
onOk: () => {
|
||||
var url=APIConfig.BschClassSystem.majorsdelete+this.majorTableData[index].id;
|
||||
this.$api.post(url,{},(resp)=>{
|
||||
this.$Message.success('删除成功!');
|
||||
this.getmajorslist();
|
||||
});
|
||||
this.$nextTick(() => this.initTableDrag())
|
||||
}
|
||||
})
|
||||
},
|
||||
searchMajor() {
|
||||
this.majorPageNum = 1
|
||||
this.$nextTick(() => this.initTableDrag());
|
||||
this.getmajorslist();
|
||||
},
|
||||
majorPageChange(page) {
|
||||
this.majorPageNum = page
|
||||
this.$nextTick(() => this.initTableDrag())
|
||||
},
|
||||
majorSizeChange(size) {
|
||||
this.majorPageSize = size
|
||||
this.majorPageNum = 1
|
||||
this.$nextTick(() => this.initTableDrag())
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-wrap {
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.page-title {
|
||||
margin: 0 0 12px;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.tab-panel {
|
||||
margin-top: 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.btn-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
}
|
||||
.drag-box {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
/* 悬浮删除容器 */
|
||||
.tag-wrap {
|
||||
position: relative;
|
||||
cursor: move;
|
||||
user-select: none;
|
||||
}
|
||||
.tag-btn {
|
||||
border: 1px solid #666;
|
||||
padding: 8px 22px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
background: #f56c6c;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
line-height: 18px;
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.tag-wrap:hover .close-btn {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
padding: 8px 22px;
|
||||
}
|
||||
.tip-info {
|
||||
margin-top: 30px;
|
||||
color: #999;
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
::v-deep .drag-ghost {
|
||||
opacity: 0.4;
|
||||
background: #cde4ff;
|
||||
}
|
||||
|
||||
/* 专业布局 */
|
||||
.major-adapt-wrap {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 0px;
|
||||
min-height: 0;
|
||||
}
|
||||
.major-top-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 14px;
|
||||
flex-shrink: 0;
|
||||
background: #F7F7F7;
|
||||
padding: 10px;
|
||||
}
|
||||
.search-box {
|
||||
width: 260px;
|
||||
}
|
||||
.table-scroll-box {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.major-table {
|
||||
width: 100%;
|
||||
}
|
||||
.drag-icon {
|
||||
cursor: move;
|
||||
margin-left: 8px;
|
||||
font-size: 18px;
|
||||
}
|
||||
/* 关键:穿透scoped,Sortable能识别把手 */
|
||||
::v-deep .drag-handle {
|
||||
cursor: grab !important;
|
||||
}
|
||||
::v-deep .table-drag-ghost {
|
||||
background-color: #e8f3ff !important;
|
||||
}
|
||||
.pagination-fixed-bottom {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin-top: 14px;
|
||||
gap: 12px;
|
||||
}
|
||||
.total-desc {
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div style="height:100%;">
|
||||
<Christianity v-if="type==1"></Christianity>
|
||||
<HigherEducation v-if="type==2"></HigherEducation>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Christianity from "./studentManage/Christianity";
|
||||
import HigherEducation from "./studentManage/HigherEducation";
|
||||
export default {
|
||||
name: 'studentManage',
|
||||
components: { Christianity,HigherEducation },
|
||||
data() {
|
||||
return {
|
||||
type:0,
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.getType();
|
||||
},
|
||||
methods: {
|
||||
//获取学制
|
||||
getType:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getType, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.type = resp.data;
|
||||
}else{
|
||||
_this.type=1;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,905 @@
|
||||
<template>
|
||||
<div class="student-manage-wrap">
|
||||
<!-- 左侧树形区域 固定高度滚动 -->
|
||||
<div class="left-tree-box">
|
||||
<my-tree :treeData="treeData" :selectId="selectnodeid" @on-tree-click="treeLink"></my-tree>
|
||||
</div>
|
||||
|
||||
<!-- 右侧主体区域 -->
|
||||
<div class="right-main-box">
|
||||
<!-- 顶部按钮+搜索栏 -->
|
||||
<div class="top-bar">
|
||||
|
||||
<div class="search-wrap" style="width: 100%;">
|
||||
<div class="btn-left-group fl">
|
||||
<Button type="primary" @click="openAddStudent">添加学生</Button>
|
||||
<Button type="success" style="margin-left:8px" @click="openImportModal">学生导入</Button>
|
||||
<Button type="success" style="margin-left:8px" @click="openStuIdImportModal">学号导入</Button>
|
||||
<Button type="primary" style="margin-left:8px" @click="batchTransferStudent">转出学生</Button>
|
||||
<Button type="primary" style="margin-left:8px" @click="openMoveClassModal">学生调班</Button>
|
||||
<Button type="error" style="margin-left:8px" @click="openChangeStatusModal">学生异动</Button>
|
||||
</div>
|
||||
<Input
|
||||
class="fr"
|
||||
v-model="searchKey"
|
||||
placeholder="姓名,身份证,账号"
|
||||
search
|
||||
style="width:300px"
|
||||
@on-search="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格容器:自适应剩余高度滚动 -->
|
||||
<div class="table-scroll-wrap">
|
||||
<Table
|
||||
border
|
||||
stripe
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
:height="useTableHeight()+22"
|
||||
@on-selection-change="selectionChange"
|
||||
></Table>
|
||||
</div>
|
||||
|
||||
<!-- 左下角批量删除 + 底部分页固定 -->
|
||||
<div class="bottom-bar">
|
||||
<Button type="error" @click="batchDelete">删除</Button>
|
||||
<div class="page-right">
|
||||
<span style="margin-right:12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,40,50]"
|
||||
show-sizer
|
||||
@on-change="pageChange"
|
||||
@on-page-size-change="sizeChange"
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗1:添加学生 -->
|
||||
<Modal v-model="addModalVisible" title="添加学生" width="560">
|
||||
<Form ref="addForm" :model="addForm" :rules="formRules" label-width="90">
|
||||
<FormItem label="年级" prop="grade">
|
||||
<Select v-model="addForm.grade" style="width:100%" @on-change="getschclassselect">
|
||||
<Option v-for="item in gradeselectlist" :key="item.id" :value="item.id+''">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="班级" prop="classId">
|
||||
<Select v-model="addForm.classId" style="width:100%">
|
||||
<Option v-for="item in schclassselectlist" :key="item.id" :value="item.id+''">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="学生姓名" prop="name">
|
||||
<Input v-model="addForm.name" placeholder="请输入学生姓名"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="学号">
|
||||
<Input v-model="addForm.stuClassNo" placeholder="请输入当前学号"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="身份证号">
|
||||
<Input v-model="addForm.idCard" placeholder="请输入身份证号"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="账号" prop="account">
|
||||
<Input v-model="addForm.account" placeholder="请输入账号"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="密码" prop="pwd">
|
||||
<Input v-model="addForm.pwd" type="password" placeholder="请输入密码"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="addModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitAddStudent">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗2:编辑学生 -->
|
||||
<Modal v-model="editModalVisible" title="编辑学生" width="560">
|
||||
<Form ref="editForm" :model="editForm" :rules="formRules" label-width="90">
|
||||
<FormItem label="当前年级" prop="grade">
|
||||
<Select disabled v-model="editForm.grade" style="width:100%" @on-change="getschclassselect">
|
||||
<Option v-for="item in gradeselectlist" :key="item.id" :value="item.id+''">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="当前班级" prop="classId">
|
||||
<Select disabled v-model="editForm.classId" style="width:100%">
|
||||
<Option v-for="item in schclassselectlist" :key="item.id" :value="item.id+''">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="学生姓名" prop="name">
|
||||
<Input v-model="editForm.name"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="学号">
|
||||
<Input v-model="editForm.stuClassNo"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="身份证号">
|
||||
<Input v-model="editForm.idCard"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="账号" prop="account">
|
||||
<Input v-model="editForm.account"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="editModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitEditStudent">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗3:学生信息导入 -->
|
||||
<Modal v-model="importModalVisible" title="学生信息导入" width="520">
|
||||
<!-- <div style="padding:10px 0;">
|
||||
<div style="display:flex;align-items:center;">
|
||||
<Upload action="" :before-upload="beforeFileUpload">
|
||||
<Button>选择要上传的文件</Button>
|
||||
</Upload>
|
||||
<a href="javascript:;" style="margin-left:20px;color:#2d7ff9" @click="downloadStuTemplate">点击链接下载[用户导入模板.xls]</a>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="importModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="confirmImport">确定</Button>
|
||||
</div> -->
|
||||
<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="stuIdImportModalVisible" title="学生学号导入" width="520">
|
||||
<div class="main-contents">
|
||||
<Form ref="UpParmas2.datapre" :model="UpParmas2.datapre" :label-width="100" inline>
|
||||
<FormItem label="Excel上传:" style="margin-bottom:10px;width:100%;">
|
||||
<i-input type="text" style="width:90%;" v-model="UpParmas2.fileName" class="import-input" placeholder="未选中任何文件.." readonly></i-input>
|
||||
<Upload class="fr btn"
|
||||
:action="UpParmas2.actionUrl"
|
||||
:data="UpParmas2.datapre"
|
||||
:show-upload-list="false"
|
||||
:headers="uploadHeader"
|
||||
accept=".xls,.xlsx"
|
||||
:before-upload="handleUpload2"
|
||||
:on-success="importFile2"
|
||||
>
|
||||
<i-button icon="md-add"></i-button>
|
||||
</Upload>
|
||||
</FormItem>
|
||||
<FormItem v-if="UpParmas2.listData.data!=null" style="margin-bottom:10px">
|
||||
<div v-if="UpParmas2.listData.code==0" style="color:red">导入失败,请修改Excel文件中相关数据后再重新上传!</div>
|
||||
<div v-if="UpParmas2.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="MoBanExceldaochu2" style="font-size:12px;">点击链接下载[学生学号信息导入模板.xls]</a>
|
||||
</template>
|
||||
</Alert>
|
||||
|
||||
<Table :columns="UpParmas2.columns" :data="UpParmas2.listData.data" v-if="UpParmas2.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="UpfileModalcloseclick2" style="margin-left: 8px">关闭</i-Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗5:学生调班 -->
|
||||
<Modal v-model="moveClassModalVisible" title="学生调班" width="500">
|
||||
<div style="padding:10px 0;">
|
||||
<div style="margin-bottom:16px;display:flex;align-items:center;">
|
||||
<span style="width:90px;">当前班级</span>
|
||||
<Input v-model="currentSelectClass" disabled style="flex:1;"></Input>
|
||||
</div>
|
||||
<div>
|
||||
<span style="width:90px;display:inline-block;margin-bottom:10px;">目标班级</span>
|
||||
<div class="class-btn-wrap">
|
||||
<Button
|
||||
v-for="item in filterschclassselectlist"
|
||||
:key="item.id"
|
||||
:type="targetClass===item.id?'primary':'default'"
|
||||
style="margin:6px"
|
||||
@click="targetClass=item.id"
|
||||
size="small"
|
||||
>{{ item.name }}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="moveClassModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitMoveClass">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗6:学生异动 -->
|
||||
<Modal v-model="changeStatusModalVisible" title="学生异动" width="520">
|
||||
<div style="padding:10px 0;">
|
||||
<div style="margin-bottom:16px;display:flex;align-items:center;">
|
||||
<span style="width:90px;">当前学生</span>
|
||||
<Input v-model="currentStuName" disabled style="flex:1;"></Input>
|
||||
</div>
|
||||
<div>
|
||||
<span style="width:90px;display:inline-block;margin-bottom:10px;">异动情况</span>
|
||||
<div class="status-btn-wrap">
|
||||
<Button
|
||||
v-for="item in studentabnormallist"
|
||||
:key="item.id"
|
||||
:type="selectedStatus===item.id?'primary':'default'"
|
||||
style="margin:6px"
|
||||
@click="selectedStatus=item.id"
|
||||
size="small"
|
||||
>{{ item.name }}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="changeStatusModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitChangeStatus">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗7:转出学生弹窗 -->
|
||||
<Modal v-model="transferStudentModal" title="转出学生" width="420">
|
||||
<p>确认将选中学生做转出操作?</p>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="transferStudentModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="confirmTransferStudent">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myTree from "../../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: 'StudentManage',
|
||||
components: { myTree },
|
||||
data() {
|
||||
return {
|
||||
// 左侧树形数据
|
||||
treeData: [],
|
||||
selectnodeid:'',
|
||||
schsystemId:'',
|
||||
gradeId:'',
|
||||
classId:'',
|
||||
gradeselectlist:[],
|
||||
classOptionList: [],
|
||||
|
||||
// 搜索
|
||||
searchKey: '',
|
||||
|
||||
// 分页
|
||||
pageNum: 1,
|
||||
pageSize: 40,
|
||||
total: 0,
|
||||
selectedRows: [],
|
||||
|
||||
// 表格列配置
|
||||
tableColumns: [],
|
||||
tableData: [],
|
||||
spinShow:false,
|
||||
UpParmas:{
|
||||
fileName:'',
|
||||
listData:{},
|
||||
datapre:{},
|
||||
actionUrl:APIConfig.BschClassSystem.importStudents,
|
||||
columns:[
|
||||
{
|
||||
title: '行号',
|
||||
key: 'rows',
|
||||
align: 'center',
|
||||
width:'80'
|
||||
},
|
||||
{
|
||||
title: '内容',
|
||||
key: 'columnValue',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '错误详情',
|
||||
key: 'errorMsg',
|
||||
align: 'center',
|
||||
}
|
||||
],
|
||||
},
|
||||
UpParmas2:{
|
||||
fileName:'',
|
||||
listData:{},
|
||||
datapre:{},
|
||||
actionUrl:APIConfig.BschClassSystem.importStudentClassNo,
|
||||
columns:[
|
||||
{
|
||||
title: '行号',
|
||||
key: 'rows',
|
||||
align: 'center',
|
||||
width:'80'
|
||||
},
|
||||
{
|
||||
title: '内容',
|
||||
key: 'columnValue',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '错误详情',
|
||||
key: 'errorMsg',
|
||||
align: 'center',
|
||||
}
|
||||
],
|
||||
},
|
||||
|
||||
// 弹窗开关
|
||||
addModalVisible: false,
|
||||
editModalVisible: false,
|
||||
importModalVisible: false,
|
||||
stuIdImportModalVisible: false,
|
||||
moveClassModalVisible: false,
|
||||
changeStatusModalVisible: false,
|
||||
transferStudentModal:false,
|
||||
|
||||
// 新增学生表单
|
||||
addForm: { grade:'', classId:'', name:'', stuClassNo:'', idCard:'', account:'', pwd:'' },
|
||||
// 编辑学生表单
|
||||
editForm: { grade:'', classId:'', name:'', stuClassNo:'', idCard:'', account:'', id:null,stuId:0,status:1 },
|
||||
|
||||
// 调班弹窗
|
||||
currentSelectClass: '',
|
||||
targetClass: '',
|
||||
// 异动弹窗
|
||||
currentStuName: '',
|
||||
selectedStatus: 1,
|
||||
studentabnormallist: [],
|
||||
formRules: {
|
||||
grade: [{ required: true, message: '请选择年级', trigger: 'change' }],
|
||||
classId: [{ required: true, message: '请选择班级', trigger: 'change' }],
|
||||
name: [{ required: true, message: '请输入学生姓名', trigger: 'blur' }],
|
||||
account: [{ required: true, message: '请输入账号', trigger: 'blur' }],
|
||||
pwd: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
||||
}
|
||||
}
|
||||
},
|
||||
mixins: [self_viewport],
|
||||
computed: {
|
||||
uploadHeader() { //附件上传header
|
||||
let config = {};
|
||||
if (localStorage.getItem("currentRole")) {
|
||||
let currentRole = localStorage.getItem("currentRole");
|
||||
config["currentRole"] = currentRole;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getgradeselect();
|
||||
this.getClassTree();
|
||||
this.initTableColumn()
|
||||
},
|
||||
methods: {
|
||||
//获取年级下拉
|
||||
getgradeselect:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getgradeselect, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.gradeselectlist=resp.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取班级下拉
|
||||
getschclassselect:function(){
|
||||
const _this = this;
|
||||
var item={
|
||||
gradeId:_this.gradeId
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getschclassselect, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.schclassselectlist=resp.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取学生状态列表
|
||||
getstudentabnormal:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getstudentabnormal, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.studentabnormallist=resp.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取班级树
|
||||
getClassTree:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getClassTree, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.treeData=resp.data;
|
||||
if(resp.data.children.length>0){
|
||||
// 起始节点为 data
|
||||
const pathArr = _this.getFirstPath(resp.data);
|
||||
_this.schsystemId=pathArr[pathArr.length-1].schsystemId;
|
||||
_this.gradeId=pathArr[pathArr.length-1].gradeId+'';
|
||||
_this.classId=pathArr[pathArr.length-1].classId+'';
|
||||
_this.selectnodeid=pathArr[pathArr.length-1].id;
|
||||
_this.getschclassselect();
|
||||
_this.loadData();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取最后一级的map
|
||||
getFirstPath(rootNode) {
|
||||
const path = [];
|
||||
let cur = rootNode;
|
||||
while (cur) {
|
||||
// 存入当前层级关键信息
|
||||
path.push({
|
||||
id: cur.id,
|
||||
name: cur.name,
|
||||
type: cur.type,
|
||||
schsystemId:cur.schsystemId,
|
||||
gradeId:cur.gradeId,
|
||||
classId:cur.classId,
|
||||
});
|
||||
// 有子节点就取第一个,没有就终止
|
||||
if (cur.children && cur.children.length > 0) {
|
||||
cur = cur.children[0];
|
||||
} else {
|
||||
cur = null;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
},
|
||||
// 初始化表格列 配置式columns
|
||||
initTableColumn() {
|
||||
this.tableColumns = [
|
||||
{type: 'selection',width: 55,align: 'center'},
|
||||
{ title: '姓名', key: 'name', align: 'center' },
|
||||
{ title: '用户名', key: 'account', align: 'center' },
|
||||
{ title: '学号', key: 'stuClassNo', align: 'center', width: 140 },
|
||||
{ title: '身份证', key: 'idCard', align: 'center' },
|
||||
{ title: '班级', key: 'className', align: 'center' },
|
||||
{ title: '状态', key: 'statusName', align: 'center', width: 90 },
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
width: 80,
|
||||
render: (h, params) => {
|
||||
return h('Button', {
|
||||
props: { type: 'text', icon: 'md-create', size: 'large' },
|
||||
on: { click: () => this.openEditStudent(params.row) }
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// 树形选中切换
|
||||
treeLink(treeNode) {
|
||||
this.schsystemId=treeNode.schsystemId;
|
||||
this.gradeId=treeNode.gradeId?treeNode.gradeId+'':'';
|
||||
this.classId=treeNode.classId?treeNode.classId+'':'';
|
||||
this.selectnodeid=treeNode.id;
|
||||
this.pageNum = 1
|
||||
this.loadData()
|
||||
},
|
||||
|
||||
// 多选行回调
|
||||
selectionChange(rows) {
|
||||
this.selectedRows = rows
|
||||
},
|
||||
|
||||
// 加载列表数据
|
||||
loadData() {
|
||||
const _this = this;
|
||||
var item = {
|
||||
schsystemId:_this.schsystemId,
|
||||
gradeId:_this.gradeId,
|
||||
classId:_this.classId,
|
||||
keyword:_this.searchKey,
|
||||
page:_this.pageNum-1,
|
||||
size:_this.pageSize
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getstudentsearch, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.tableData = resp.data.content;
|
||||
_this.total=resp.data.total;
|
||||
} else {
|
||||
_this.tableData = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.pageNum = 1;
|
||||
this.loadData();
|
||||
},
|
||||
|
||||
// 分页切换
|
||||
pageChange(p) {
|
||||
this.pageNum = p
|
||||
this.loadData()
|
||||
},
|
||||
sizeChange(size) {
|
||||
this.pageSize = size
|
||||
this.pageNum = 1
|
||||
this.loadData()
|
||||
},
|
||||
|
||||
// 新增学生
|
||||
openAddStudent() {
|
||||
this.addModalVisible = true;
|
||||
this.addForm = { grade:this.gradeId+'', classId:this.classId+'', name:'', stuClassNo:'', idCard:'', account:'', pwd:'' }
|
||||
},
|
||||
submitAddStudent() {
|
||||
this.$refs.addForm.validate(valid => {
|
||||
if (!valid) return;
|
||||
// 新增
|
||||
const newItem = {
|
||||
classId:this.addForm.classId,
|
||||
name:this.addForm.name,
|
||||
stuClassNo:this.addForm.stuClassNo,
|
||||
idCard:this.addForm.idCard,
|
||||
account:this.addForm.account,
|
||||
pwd:this.addForm.pwd,
|
||||
stuId:0,
|
||||
status:1
|
||||
}
|
||||
const url = APIConfig.BschClassSystem.studentsave;
|
||||
this.$api.post(url, JSON.stringify(newItem), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("新增学生成功!");
|
||||
this.addModalVisible = false
|
||||
this.loadData();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
|
||||
// 编辑学生
|
||||
openEditStudent(row) {
|
||||
this.editModalVisible = true
|
||||
this.editForm = {
|
||||
id: row.id,
|
||||
grade:row.gradeId+'',
|
||||
classId: row.classId+'',
|
||||
name: row.name,
|
||||
stuId: row.stuId,
|
||||
idCard: row.idCard,
|
||||
stuClassNo:row.stuClassNo,
|
||||
account: row.account,
|
||||
status:row.status
|
||||
}
|
||||
},
|
||||
submitEditStudent() {
|
||||
this.$refs.editForm.validate(valid => {
|
||||
if (!valid) return;
|
||||
// 编辑
|
||||
const newItem = {
|
||||
id: this.editForm.id,
|
||||
classId:this.editForm.classId,
|
||||
name:this.editForm.name,
|
||||
stuClassNo:this.editForm.stuClassNo,
|
||||
idCard:this.editForm.idCard,
|
||||
account:this.editForm.account,
|
||||
stuId:this.editForm.stuId,
|
||||
status:this.editForm.status
|
||||
}
|
||||
const url = APIConfig.BschClassSystem.studentsave;
|
||||
this.$api.post(url, JSON.stringify(newItem), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("编辑保存成功!");
|
||||
this.editModalVisible = false
|
||||
this.loadData();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
|
||||
// 批量删除
|
||||
batchDelete() {
|
||||
if (!this.selectedRows.length) {
|
||||
return this.$Message.warning('请先勾选学生')
|
||||
}
|
||||
this.$Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定删除选中学生?删除不可恢复',
|
||||
onOk: () => {
|
||||
let idlist=this.selectedRows.map(a=>a.id);
|
||||
const url = APIConfig.BschClassSystem.studentdelete+idlist.join(',');
|
||||
this.$api.post(url,{}, resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("删除成功!");
|
||||
this.selectedRows = []
|
||||
this.loadData()
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 学生导入
|
||||
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.loadData()
|
||||
}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.studentdownloadTemplate+'?schId='+schId;
|
||||
window.location.href=url;
|
||||
}else{
|
||||
this.$Message.info('获取不了学校!');
|
||||
}
|
||||
},
|
||||
//附件上传模态框关闭事件
|
||||
UpfileModalcloseclick:function(){
|
||||
this.importModalVisible=false;
|
||||
this.UpParmas={
|
||||
fileName:'',
|
||||
listData:{},
|
||||
datapre:{},
|
||||
}
|
||||
},
|
||||
//按照学生学号导入
|
||||
openStuIdImportModal() { this.stuIdImportModalVisible = true },
|
||||
//导入成功返回
|
||||
importFil2(response, file, fileList){
|
||||
const _this=this;
|
||||
console.log(response);
|
||||
console.log(file);
|
||||
_this.spinShow=false;
|
||||
_this.UpParmas2.fileName=file.name;
|
||||
_this.UpParmas2.listData=response;
|
||||
if(response.State)
|
||||
{
|
||||
_this.$Message.info('导入成功!');
|
||||
_this.loadData()
|
||||
}else{
|
||||
_this.$Message.info(response.Message);
|
||||
}
|
||||
},
|
||||
//附件上传之前的方法
|
||||
handleUpload2:function(file){
|
||||
const _this=this;
|
||||
_this.spinShow=true;
|
||||
},
|
||||
MoBanExceldaochu2() {
|
||||
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.studentClassNoTemplate+'?schId='+schId;
|
||||
window.location.href=url;
|
||||
}else{
|
||||
this.$Message.info('获取不了学校!');
|
||||
}
|
||||
},
|
||||
//附件上传模态框关闭事件
|
||||
UpfileModalcloseclick2:function(){
|
||||
this.stuIdImportModalVisible=false;
|
||||
this.UpParmas2={
|
||||
fileName:'',
|
||||
listData:{},
|
||||
datapre:{},
|
||||
}
|
||||
},
|
||||
//学生转出
|
||||
batchTransferStudent(){
|
||||
if (!this.selectedRows.length) return this.$Message.warning('请勾选学生');
|
||||
this.transferStudentModal = true
|
||||
},
|
||||
//转出事件
|
||||
confirmTransferStudent() {
|
||||
const idlist = this.selectedRows.map(i => i.id);
|
||||
const url = APIConfig.BschClassSystem.studenttransferOut+idlist.join(',');
|
||||
this.$api.post(url,{}, resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("转出操作完成!");
|
||||
this.selectedRows = [];
|
||||
this.transferStudentModal = false;
|
||||
this.loadData();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
// 学生调班
|
||||
openMoveClassModal() {
|
||||
if (!this.selectedRows.length) return this.$Message.warning('请勾选学生');
|
||||
this.moveClassModalVisible = true;
|
||||
this.currentSelectClass = this.selectedRows[0].className;
|
||||
this.filterschclassselectlist=this.schclassselectlist.filter(item => item.id != this.classId);
|
||||
this.targetClass = '';
|
||||
},
|
||||
submitMoveClass() {
|
||||
if (!this.targetClass) return this.$Message.warning('请选择目标班级')
|
||||
const newItem = {
|
||||
transferClassId: this.targetClass,
|
||||
stuIds:this.selectedRows.map(a=>a.id)
|
||||
}
|
||||
const url = APIConfig.BschClassSystem.studenttransferClass;
|
||||
this.$api.post(url, JSON.stringify(newItem), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("调班成功!");
|
||||
this.moveClassModalVisible = false
|
||||
this.selectedRows = []
|
||||
this.loadData()
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 学生异动
|
||||
openChangeStatusModal() {
|
||||
if (!this.selectedRows.length) return this.$Message.warning('请勾选学生');
|
||||
this.changeStatusModalVisible = true;
|
||||
this.currentStuName = this.selectedRows[0].name;
|
||||
this.getstudentabnormal();
|
||||
this.selectedStatus = 1;
|
||||
},
|
||||
submitChangeStatus() {
|
||||
const newItem = {
|
||||
abnormalStatus: this.selectedStatus,
|
||||
stuIds:this.selectedRows.map(a=>a.id)
|
||||
}
|
||||
const url = APIConfig.BschClassSystem.studentsetAbnormalStatus;
|
||||
this.$api.post(url, JSON.stringify(newItem), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success('异动状态修改完成');
|
||||
this.changeStatusModalVisible = false;
|
||||
this.selectedRows = [];
|
||||
this.loadData();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.student-manage-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
box-sizing: border-box;
|
||||
padding: 12px;
|
||||
}
|
||||
/* 左侧树固定高度 */
|
||||
.left-tree-box {
|
||||
width: 260px;
|
||||
border: 1px solid #e6e6e6;
|
||||
overflow-y: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
/* 右侧整体弹性布局 */
|
||||
.right-main-box {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
/* 顶部栏 */
|
||||
.top-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 0;
|
||||
margin-bottom: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.btn-left-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
/* 表格自适应滚动容器 */
|
||||
.table-scroll-wrap {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
height: 100%;
|
||||
}
|
||||
/* 底部栏:分页固定底部 */
|
||||
.bottom-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.page-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
/* 调班、异动弹窗按钮排版 */
|
||||
.class-btn-wrap, .status-btn-wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.ivu-alert-desc{
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,890 @@
|
||||
<template>
|
||||
<div class="student-manage-wrap">
|
||||
<!-- 左侧树形区域 固定高度滚动 -->
|
||||
<div class="left-tree-box">
|
||||
<my-tree :treeData="treeData" :selectId="selectnodeid" @on-tree-click="treeLink"></my-tree>
|
||||
</div>
|
||||
|
||||
<!-- 右侧主体区域 -->
|
||||
<div class="right-main-box">
|
||||
<!-- 顶部按钮+搜索栏 -->
|
||||
<div class="top-bar">
|
||||
<div class="search-wrap" style="width: 100%;">
|
||||
<div class="btn-left-group fl">
|
||||
<Button type="primary" @click="openAddStudent">添加学生</Button>
|
||||
<Button type="success" style="margin-left:8px" @click="openImportModal">学生导入</Button>
|
||||
<Button type="success" style="margin-left:8px" @click="openStuIdImportModal">学号导入</Button>
|
||||
<Button type="primary" style="margin-left:8px" @click="batchTransferStudent">转出学生</Button>
|
||||
<Button type="primary" style="margin-left:8px" @click="openMoveClassModal">学生调班</Button>
|
||||
<Button type="error" style="margin-left:8px" @click="openChangeStatusModal">学生异动</Button>
|
||||
</div>
|
||||
<Input
|
||||
class="fr"
|
||||
v-model="searchKey"
|
||||
placeholder="姓名,身份证,账号"
|
||||
search
|
||||
style="width:300px"
|
||||
@on-search="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格容器:自适应剩余高度滚动 -->
|
||||
<div class="table-scroll-wrap">
|
||||
<Table
|
||||
border
|
||||
stripe
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
:height="useTableHeight()+22"
|
||||
@on-selection-change="selectionChange"
|
||||
></Table>
|
||||
</div>
|
||||
|
||||
<!-- 左下角批量删除 + 底部分页固定 -->
|
||||
<div class="bottom-bar">
|
||||
<Button type="error" @click="batchDelete">删除</Button>
|
||||
<div class="page-right">
|
||||
<span style="margin-right:12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,40,50]"
|
||||
show-sizer
|
||||
@on-change="pageChange"
|
||||
@on-page-size-change="sizeChange"
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗1:添加学生 -->
|
||||
<Modal v-model="addModalVisible" title="添加学生" width="560">
|
||||
<Form ref="addForm" :model="addForm" :rules="formRules" label-width="90">
|
||||
<FormItem label="年级" prop="grade">
|
||||
<Select v-model="addForm.grade" style="width:100%" @on-change="getschclassselect">
|
||||
<Option v-for="item in gradeselectlist" :key="item.id" :value="item.id+''">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="班级" prop="classId">
|
||||
<Select v-model="addForm.classId" style="width:100%">
|
||||
<Option v-for="item in schclassselectlist" :key="item.id" :value="item.id+''">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="学生姓名" prop="name">
|
||||
<Input v-model="addForm.name" placeholder="请输入学生姓名"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="学号">
|
||||
<Input v-model="addForm.stuClassNo" placeholder="请输入当前学号"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="身份证号">
|
||||
<Input v-model="addForm.idCard" placeholder="请输入身份证号"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="账号" prop="account">
|
||||
<Input v-model="addForm.account" placeholder="请输入账号"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="密码" prop="pwd">
|
||||
<Input v-model="addForm.pwd" type="password" placeholder="请输入密码"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="addModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitAddStudent">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗2:编辑学生 -->
|
||||
<Modal v-model="editModalVisible" title="编辑学生" width="560">
|
||||
<Form ref="editForm" :model="editForm" :rules="formRules" label-width="90">
|
||||
<FormItem label="当前年级" prop="grade">
|
||||
<Select disabled v-model="editForm.grade" style="width:100%" @on-change="getschclassselect">
|
||||
<Option v-for="item in gradeselectlist" :key="item.id" :value="item.id+''">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="当前班级" prop="classId">
|
||||
<Select disabled v-model="editForm.classId" style="width:100%">
|
||||
<Option v-for="item in schclassselectlist" :key="item.id" :value="item.id+''">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="学生姓名" prop="name">
|
||||
<Input v-model="editForm.name"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="学号">
|
||||
<Input v-model="editForm.stuClassNo"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="身份证号">
|
||||
<Input v-model="editForm.idCard"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="账号" prop="account">
|
||||
<Input v-model="editForm.account"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="editModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitEditStudent">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗3:学生信息导入 -->
|
||||
<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>
|
||||
|
||||
<!-- 弹窗4:学号导入 -->
|
||||
<Modal v-model="stuIdImportModalVisible" title="学生学号导入" width="520">
|
||||
<div class="main-contents">
|
||||
<Form ref="UpParmas2.datapre" :model="UpParmas2.datapre" :label-width="100" inline>
|
||||
<FormItem label="Excel上传:" style="margin-bottom:10px;width:100%;">
|
||||
<i-input type="text" style="width:90%;" v-model="UpParmas2.fileName" class="import-input" placeholder="未选中任何文件.." readonly></i-input>
|
||||
<Upload class="fr btn"
|
||||
:action="UpParmas2.actionUrl"
|
||||
:data="UpParmas2.datapre"
|
||||
:show-upload-list="false"
|
||||
:headers="uploadHeader"
|
||||
accept=".xls,.xlsx"
|
||||
:before-upload="handleUpload2"
|
||||
:on-success="importFile2"
|
||||
>
|
||||
<i-button icon="md-add"></i-button>
|
||||
</Upload>
|
||||
</FormItem>
|
||||
<FormItem v-if="UpParmas2.listData.data!=null" style="margin-bottom:10px">
|
||||
<div v-if="UpParmas2.listData.code==0" style="color:red">导入失败,请修改Excel文件中相关数据后再重新上传!</div>
|
||||
<div v-if="UpParmas2.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="MoBanExceldaochu2" style="font-size:12px;">点击链接下载[学生学号信息导入模板.xls]</a>
|
||||
</template>
|
||||
</Alert>
|
||||
|
||||
<Table :columns="UpParmas2.columns" :data="UpParmas2.listData.data" v-if="UpParmas2.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="UpfileModalcloseclick2" style="margin-left: 8px">关闭</i-Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗5:学生调班 -->
|
||||
<Modal v-model="moveClassModalVisible" title="学生调班" width="500">
|
||||
<div style="padding:10px 0;">
|
||||
<div style="margin-bottom:16px;display:flex;align-items:center;">
|
||||
<span style="width:90px;">当前班级</span>
|
||||
<Input v-model="currentSelectClass" disabled style="flex:1;"></Input>
|
||||
</div>
|
||||
<div>
|
||||
<span style="width:90px;display:inline-block;margin-bottom:10px;">目标班级</span>
|
||||
<div class="class-btn-wrap">
|
||||
<Button
|
||||
v-for="item in filterschclassselectlist"
|
||||
:key="item.id"
|
||||
:type="targetClass===item.id?'primary':'default'"
|
||||
style="margin:6px"
|
||||
@click="targetClass=item.id"
|
||||
size="small"
|
||||
>{{ item.name }}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="moveClassModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitMoveClass">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗6:学生异动 -->
|
||||
<Modal v-model="changeStatusModalVisible" title="学生异动" width="520">
|
||||
<div style="padding:10px 0;">
|
||||
<div style="margin-bottom:16px;display:flex;align-items:center;">
|
||||
<span style="width:90px;">当前学生</span>
|
||||
<Input v-model="currentStuName" disabled style="flex:1;"></Input>
|
||||
</div>
|
||||
<div>
|
||||
<span style="width:90px;display:inline-block;margin-bottom:10px;">异动情况</span>
|
||||
<div class="status-btn-wrap">
|
||||
<Button
|
||||
v-for="item in studentabnormallist"
|
||||
:key="item.id"
|
||||
:type="selectedStatus===item.id?'primary':'default'"
|
||||
style="margin:6px"
|
||||
@click="selectedStatus=item.id"
|
||||
size="small"
|
||||
>{{ item.name }}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="changeStatusModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitChangeStatus">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<!-- 弹窗7:转出学生弹窗 -->
|
||||
<Modal v-model="transferStudentModal" title="转出学生" width="420">
|
||||
<p>确认将选中学生做转出操作?</p>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="transferStudentModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="confirmTransferStudent">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myTree from "../../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: 'StudentManage',
|
||||
components: { myTree },
|
||||
data() {
|
||||
return {
|
||||
// 左侧树形数据
|
||||
treeData: [],
|
||||
selectnodeid:'',
|
||||
enrollYear:'',
|
||||
classId:'',
|
||||
gradeselectlist:[],
|
||||
classOptionList: [],
|
||||
|
||||
// 搜索
|
||||
searchKey: '',
|
||||
|
||||
// 分页
|
||||
pageNum: 1,
|
||||
pageSize: 40,
|
||||
total: 0,
|
||||
selectedRows: [],
|
||||
|
||||
// 表格列配置
|
||||
tableColumns: [],
|
||||
tableData: [],
|
||||
spinShow:false,
|
||||
UpParmas:{
|
||||
fileName:'',
|
||||
listData:{},
|
||||
datapre:{},
|
||||
actionUrl:APIConfig.BschClassSystem.importStudents,
|
||||
columns:[
|
||||
{
|
||||
title: '行号',
|
||||
key: 'rows',
|
||||
align: 'center',
|
||||
width:'80'
|
||||
},
|
||||
{
|
||||
title: '内容',
|
||||
key: 'columnValue',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '错误详情',
|
||||
key: 'errorMsg',
|
||||
align: 'center',
|
||||
}
|
||||
],
|
||||
},
|
||||
UpParmas2:{
|
||||
fileName:'',
|
||||
listData:{},
|
||||
datapre:{},
|
||||
actionUrl:APIConfig.BschClassSystem.importStudentClassNo,
|
||||
columns:[
|
||||
{
|
||||
title: '行号',
|
||||
key: 'rows',
|
||||
align: 'center',
|
||||
width:'80'
|
||||
},
|
||||
{
|
||||
title: '内容',
|
||||
key: 'columnValue',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '错误详情',
|
||||
key: 'errorMsg',
|
||||
align: 'center',
|
||||
}
|
||||
],
|
||||
},
|
||||
|
||||
// 弹窗开关
|
||||
addModalVisible: false,
|
||||
editModalVisible: false,
|
||||
importModalVisible: false,
|
||||
stuIdImportModalVisible: false,
|
||||
moveClassModalVisible: false,
|
||||
changeStatusModalVisible: false,
|
||||
transferStudentModal:false,
|
||||
|
||||
// 新增学生表单
|
||||
addForm: { grade:'', classId:'', name:'', stuClassNo:'', idCard:'', account:'', pwd:'' },
|
||||
// 编辑学生表单
|
||||
editForm: { grade:'', classId:'', name:'', stuClassNo:'', idCard:'', account:'', id:null,stuId:0,status:1 },
|
||||
// 调班弹窗
|
||||
currentSelectClass: '',
|
||||
targetClass: '',
|
||||
filterschclassselectlist: [],
|
||||
// 异动弹窗
|
||||
currentStuName: '',
|
||||
selectedStatus: 1,
|
||||
studentabnormallist: [],
|
||||
formRules: {
|
||||
grade: [{ required: true, message: '请选择年级', trigger: 'change' }],
|
||||
classId: [{ required: true, message: '请选择班级', trigger: 'change' }],
|
||||
name: [{ required: true, message: '请输入学生姓名', trigger: 'blur' }],
|
||||
account: [{ required: true, message: '请输入账号', trigger: 'blur' }],
|
||||
pwd: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
||||
}
|
||||
}
|
||||
},
|
||||
mixins: [self_viewport],
|
||||
computed: {
|
||||
uploadHeader() { //附件上传header
|
||||
let config = {};
|
||||
if (localStorage.getItem("currentRole")) {
|
||||
let currentRole = localStorage.getItem("currentRole");
|
||||
config["currentRole"] = currentRole;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getgradeselect();
|
||||
this.getClassTree();
|
||||
this.initTableColumn()
|
||||
},
|
||||
methods: {
|
||||
//获取年级下拉
|
||||
getgradeselect:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getgradeselect, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.gradeselectlist=resp.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取班级下拉
|
||||
getschclassselect:function(){
|
||||
const _this = this;
|
||||
var item={
|
||||
gradeId:_this.enrollYear
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getschclassselect, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.schclassselectlist=resp.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取学生状态列表
|
||||
getstudentabnormal:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getstudentabnormal, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.studentabnormallist=resp.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取班级树
|
||||
getClassTree:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getHigherSchClassTree, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.treeData=resp.data;
|
||||
if(resp.data.children.length>0){
|
||||
// 起始节点为 data
|
||||
const pathArr = _this.getFirstPath(resp.data);
|
||||
_this.enrollYear=pathArr[pathArr.length-1].enrollYear+'',
|
||||
_this.classId=pathArr[pathArr.length-1].classId;
|
||||
_this.selectnodeid=pathArr[pathArr.length-1].id;
|
||||
_this.getschclassselect();
|
||||
_this.loadData();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取最后一级的map
|
||||
getFirstPath(rootNode) {
|
||||
const path = [];
|
||||
let cur = rootNode;
|
||||
while (cur) {
|
||||
// 存入当前层级关键信息
|
||||
path.push({
|
||||
id: cur.id,
|
||||
name: cur.name,
|
||||
type: cur.type,
|
||||
enrollYear:cur.enrollYear,
|
||||
classId:cur.classId
|
||||
});
|
||||
// 有子节点就取第一个,没有就终止
|
||||
if (cur.children && cur.children.length > 0) {
|
||||
cur = cur.children[0];
|
||||
} else {
|
||||
cur = null;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
},
|
||||
// 初始化表格列 配置式columns
|
||||
initTableColumn() {
|
||||
this.tableColumns = [
|
||||
{
|
||||
type: 'selection',
|
||||
width: 55,
|
||||
align: 'center'
|
||||
},
|
||||
{ title: '姓名', key: 'name', align: 'center', width: 110 },
|
||||
{ title: '用户名', key: 'account', align: 'center', width: 90 },
|
||||
{ title: '学号', key: 'stuClassNo', align: 'center' },
|
||||
{ title: '身份证', key: 'idCard', align: 'center' },
|
||||
{ title: '班级', key: 'className', align: 'center' },
|
||||
{ title: '状态', key: 'statusName', align: 'center', width: 90 },
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
width: 80,
|
||||
render: (h, params) => {
|
||||
return h('Button', {
|
||||
props: { type: 'text', icon: 'md-create',type:'large' },
|
||||
on: { click: () => this.openEditStudent(params.row) }
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
// 树形选中切换
|
||||
treeLink(treeNode) {
|
||||
this.enrollYear=treeNode.enrollYear?treeNode.enrollYear+'':'';
|
||||
this.classId=treeNode.classId?treeNode.classId+'':'';
|
||||
this.selectnodeid=treeNode.id;
|
||||
this.pageNum = 1
|
||||
this.loadData()
|
||||
},
|
||||
// 多选行回调
|
||||
selectionChange(rows) {
|
||||
this.selectedRows = rows
|
||||
},
|
||||
|
||||
// 加载列表数据
|
||||
loadData() {
|
||||
const _this = this;
|
||||
var item = {
|
||||
year:_this.enrollYear,
|
||||
classId:_this.classId,
|
||||
keyword:_this.keyword,
|
||||
page:_this.pageNum-1,
|
||||
size:_this.pageSize
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.gethigherSchSearch, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.tableData = resp.data.content;
|
||||
_this.total=resp.data.total;
|
||||
} else {
|
||||
_this.tableData = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.pageNum = 1
|
||||
this.loadData()
|
||||
},
|
||||
|
||||
// 分页切换
|
||||
pageChange(p) {
|
||||
this.pageNum = p
|
||||
this.loadData()
|
||||
},
|
||||
sizeChange(size) {
|
||||
this.pageSize = size
|
||||
this.pageNum = 1
|
||||
this.loadData()
|
||||
},
|
||||
|
||||
// 新增学生
|
||||
openAddStudent() {
|
||||
this.addModalVisible = true;
|
||||
this.addForm = { grade:this.enrollYear+'', classId:this.classId+'', name:'', stuClassNo:'', idCard:'', account:'', pwd:'' }
|
||||
},
|
||||
submitAddStudent() {
|
||||
this.$refs.addForm.validate(valid => {
|
||||
if (!valid) return;
|
||||
// 新增
|
||||
const newItem = {
|
||||
classId:this.addForm.classId,
|
||||
name:this.addForm.name,
|
||||
stuClassNo:this.addForm.stuClassNo,
|
||||
idCard:this.addForm.idCard,
|
||||
account:this.addForm.account,
|
||||
pwd:this.addForm.pwd,
|
||||
stuId:0,
|
||||
status:1
|
||||
}
|
||||
const url = APIConfig.BschClassSystem.studentsave;
|
||||
this.$api.post(url, JSON.stringify(newItem), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("新增学生成功!");
|
||||
this.addModalVisible = false
|
||||
this.loadData();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
|
||||
// 编辑学生
|
||||
openEditStudent(row) {
|
||||
this.editModalVisible = true
|
||||
this.editForm = {
|
||||
id: row.id,
|
||||
grade:row.gradeId+'',
|
||||
classId: row.classId+'',
|
||||
name: row.name,
|
||||
stuId: row.stuId,
|
||||
idCard: row.idCard,
|
||||
stuClassNo:row.stuClassNo,
|
||||
account: row.account,
|
||||
status:row.status
|
||||
}
|
||||
},
|
||||
submitEditStudent() {
|
||||
this.$refs.editForm.validate(valid => {
|
||||
if (!valid) return;
|
||||
// 编辑
|
||||
const newItem = {
|
||||
id: this.editForm.id,
|
||||
classId:this.editForm.classId,
|
||||
name:this.editForm.name,
|
||||
stuClassNo:this.editForm.stuClassNo,
|
||||
idCard:this.editForm.idCard,
|
||||
account:this.editForm.account,
|
||||
stuId:this.editForm.stuId,
|
||||
status:this.editForm.status
|
||||
}
|
||||
const url = APIConfig.BschClassSystem.studentsave;
|
||||
this.$api.post(url, JSON.stringify(newItem), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("编辑保存成功!");
|
||||
this.editModalVisible = false
|
||||
this.loadData();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
|
||||
// 批量删除
|
||||
batchDelete() {
|
||||
if (!this.selectedRows.length) {
|
||||
return this.$Message.warning('请先勾选学生')
|
||||
}
|
||||
this.$Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定删除选中学生?删除不可恢复',
|
||||
onOk: () => {
|
||||
let idlist=this.selectedRows.map(a=>a.id);
|
||||
const url = APIConfig.BschClassSystem.studentdelete+idlist.join(',');
|
||||
this.$api.post(url,{}, resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("删除成功!");
|
||||
this.selectedRows = []
|
||||
this.loadData()
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 学生导入
|
||||
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.loadData()
|
||||
}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.studentdownloadTemplate+'?schId='+schId;
|
||||
window.location.href=url;
|
||||
}else{
|
||||
this.$Message.info('获取不了学校!');
|
||||
}
|
||||
},
|
||||
//附件上传模态框关闭事件
|
||||
UpfileModalcloseclick:function(){
|
||||
this.importModalVisible=false;
|
||||
this.UpParmas={
|
||||
fileName:'',
|
||||
listData:{},
|
||||
datapre:{},
|
||||
}
|
||||
},
|
||||
//按照学生学号导入
|
||||
openStuIdImportModal() { this.stuIdImportModalVisible = true },
|
||||
//导入成功返回
|
||||
importFil2(response, file, fileList){
|
||||
const _this=this;
|
||||
console.log(response);
|
||||
console.log(file);
|
||||
_this.spinShow=false;
|
||||
_this.UpParmas2.fileName=file.name;
|
||||
_this.UpParmas2.listData=response;
|
||||
if(response.State)
|
||||
{
|
||||
_this.$Message.info('导入成功!');
|
||||
_this.loadData()
|
||||
}else{
|
||||
_this.$Message.info(response.Message);
|
||||
}
|
||||
},
|
||||
//附件上传之前的方法
|
||||
handleUpload2:function(file){
|
||||
const _this=this;
|
||||
_this.spinShow=true;
|
||||
},
|
||||
MoBanExceldaochu2() {
|
||||
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.studentClassNoTemplate+'?schId='+schId;
|
||||
window.location.href=url;
|
||||
}else{
|
||||
this.$Message.info('获取不了学校!');
|
||||
}
|
||||
},
|
||||
//附件上传模态框关闭事件
|
||||
UpfileModalcloseclick2:function(){
|
||||
this.stuIdImportModalVisible=false;
|
||||
this.UpParmas2={
|
||||
fileName:'',
|
||||
listData:{},
|
||||
datapre:{},
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
//学生转出
|
||||
batchTransferStudent(){
|
||||
if (!this.selectedRows.length) return this.$Message.warning('请勾选学生');
|
||||
this.transferStudentModal = true
|
||||
},
|
||||
//转出事件
|
||||
confirmTransferStudent() {
|
||||
const idlist = this.selectedRows.map(i => i.id);
|
||||
const url = APIConfig.BschClassSystem.studenttransferOut+idlist.join(',');
|
||||
this.$api.post(url,{}, resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("转出操作完成!");
|
||||
this.selectedRows = [];
|
||||
this.transferStudentModal = false;
|
||||
this.loadData();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
// 学生调班
|
||||
openMoveClassModal() {
|
||||
if (!this.selectedRows.length) return this.$Message.warning('请勾选学生');
|
||||
this.filterschclassselectlist=[...this.schclassselectlist].filter(item => item.id != this.classId);
|
||||
this.moveClassModalVisible = true;
|
||||
this.currentSelectClass = this.selectedRows[0].className;
|
||||
this.targetClass = '';
|
||||
},
|
||||
submitMoveClass() {
|
||||
if (!this.targetClass) return this.$Message.warning('请选择目标班级');
|
||||
const newItem = {
|
||||
transferClassId: this.targetClass,
|
||||
stuIds:this.selectedRows.map(a=>a.id)
|
||||
}
|
||||
const url = APIConfig.BschClassSystem.studenttransferClass;
|
||||
this.$api.post(url, JSON.stringify(newItem), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("调班成功!");
|
||||
this.moveClassModalVisible = false
|
||||
this.selectedRows = []
|
||||
this.loadData()
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 学生异动
|
||||
openChangeStatusModal() {
|
||||
if (!this.selectedRows.length) return this.$Message.warning('请勾选学生');
|
||||
this.changeStatusModalVisible = true;
|
||||
this.currentStuName = this.selectedRows[0].name;
|
||||
this.getstudentabnormal();
|
||||
this.selectedStatus = 1;
|
||||
},
|
||||
submitChangeStatus() {
|
||||
const newItem = {
|
||||
abnormalStatus: this.selectedStatus,
|
||||
stuIds:this.selectedRows.map(a=>a.id)
|
||||
}
|
||||
const url = APIConfig.BschClassSystem.studentsetAbnormalStatus;
|
||||
this.$api.post(url, JSON.stringify(newItem), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success('异动状态修改完成');
|
||||
this.changeStatusModalVisible = false;
|
||||
this.selectedRows = [];
|
||||
this.loadData();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.student-manage-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
box-sizing: border-box;
|
||||
padding: 12px;
|
||||
}
|
||||
/* 左侧树固定高度 */
|
||||
.left-tree-box {
|
||||
width: 260px;
|
||||
border: 1px solid #e6e6e6;
|
||||
overflow-y: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
/* 右侧整体弹性布局 */
|
||||
.right-main-box {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
/* 顶部栏 */
|
||||
.top-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 0;
|
||||
margin-bottom: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.btn-left-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
/* 表格自适应滚动容器 */
|
||||
.table-scroll-wrap {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
height: 100%;
|
||||
}
|
||||
/* 底部栏:分页固定底部 */
|
||||
.bottom-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.page-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
/* 调班、异动弹窗按钮排版 */
|
||||
.class-btn-wrap, .status-btn-wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.ivu-alert-desc{
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div style="height:100%;">
|
||||
<Christianity v-if="type==1"></Christianity>
|
||||
<HigherEducation v-if="type==2"></HigherEducation>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Christianity from "./studentYDManage/Christianity";
|
||||
import HigherEducation from "./studentYDManage/HigherEducation";
|
||||
export default {
|
||||
name: 'studentYDManage',
|
||||
components: { Christianity,HigherEducation },
|
||||
data() {
|
||||
return {
|
||||
type:0,
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.getType();
|
||||
},
|
||||
methods: {
|
||||
//获取学制
|
||||
getType:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getType, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.type = resp.data;
|
||||
}else{
|
||||
_this.type=1;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,348 @@
|
||||
<template>
|
||||
<div class="student-manage-wrap">
|
||||
<!-- 左侧树形区域 固定高度滚动 -->
|
||||
<div class="left-tree-box">
|
||||
<my-tree :treeData="treeData" :selectId="selectnodeid" @on-tree-click="treeLink"></my-tree>
|
||||
</div>
|
||||
|
||||
<!-- 右侧主体区域 -->
|
||||
<div class="right-main-box">
|
||||
<!-- 顶部按钮+搜索栏 -->
|
||||
<div class="top-bar">
|
||||
<div class="btn-left-group"></div>
|
||||
<div class="search-wrap" style="width: 100%;text-align: right;">
|
||||
<Input
|
||||
v-model="searchKey"
|
||||
placeholder="请输入学生姓名"
|
||||
search
|
||||
style="width:300px"
|
||||
@on-search="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格容器:自适应剩余高度滚动 -->
|
||||
<div class="table-scroll-wrap">
|
||||
<Table
|
||||
border
|
||||
stripe
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
:height="useTableHeight()-12"
|
||||
@on-selection-change="selectionChange"
|
||||
></Table>
|
||||
</div>
|
||||
|
||||
<!-- 左下角批量删除 + 底部分页固定 -->
|
||||
<div class="bottom-bar">
|
||||
<Button type="default" @click="selectedStatus=1;submitChangeStatus()">还原</Button>
|
||||
<div class="page-right">
|
||||
<span style="margin-right:12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,40,50]"
|
||||
show-sizer
|
||||
@on-change="pageChange"
|
||||
@on-page-size-change="sizeChange"
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗6:学生异动 -->
|
||||
<Modal v-model="changeStatusModalVisible" title="学生异动" width="520">
|
||||
<div style="padding:10px 0;">
|
||||
<div style="margin-bottom:16px;display:flex;align-items:center;">
|
||||
<span style="width:90px;">当前学生</span>
|
||||
<Input v-model="currentStuName" disabled style="flex:1;"></Input>
|
||||
</div>
|
||||
<div>
|
||||
<span style="width:90px;display:inline-block;margin-bottom:10px;">异动情况</span>
|
||||
<div class="status-btn-wrap">
|
||||
<Button
|
||||
v-for="item in studentabnormallist"
|
||||
:key="item.id"
|
||||
:type="selectedStatus===item.id?'primary':'default'"
|
||||
style="margin:6px"
|
||||
@click="selectedStatus=item.id"
|
||||
size="small"
|
||||
>{{ item.name }}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="changeStatusModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitChangeStatus">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myTree from "../../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: 'StudentManage',
|
||||
components: { myTree },
|
||||
data() {
|
||||
return {
|
||||
// 左侧树形数据
|
||||
treeData: [],
|
||||
selectnodeid:'',
|
||||
schsystemId:'',
|
||||
gradeId:'',
|
||||
classId:'',
|
||||
|
||||
// 搜索
|
||||
searchKey: '',
|
||||
|
||||
// 分页
|
||||
pageNum: 1,
|
||||
pageSize: 40,
|
||||
total: 0,
|
||||
selectedRows: [],
|
||||
|
||||
// 表格列配置
|
||||
tableColumns: [],
|
||||
tableData: [],
|
||||
|
||||
// 弹窗开关
|
||||
changeStatusModalVisible: false,
|
||||
|
||||
// 异动弹窗
|
||||
currentStuName: '',
|
||||
selectedStatus: null,
|
||||
studentabnormallist: [],
|
||||
}
|
||||
},
|
||||
mixins: [self_viewport],
|
||||
created() {
|
||||
this.getClassTree();
|
||||
this.initTableColumn()
|
||||
},
|
||||
methods: {
|
||||
//获取学生状态列表
|
||||
getstudentabnormal:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getstudentabnormal, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.studentabnormallist=resp.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取班级树
|
||||
getClassTree:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getClassTree, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.treeData=resp.data;
|
||||
if(resp.data.children.length>0){
|
||||
// 起始节点为 data
|
||||
const pathArr = _this.getFirstPath(resp.data);
|
||||
_this.schsystemId=pathArr[pathArr.length-1].schsystemId;
|
||||
_this.gradeId=pathArr[pathArr.length-1].gradeId+'';
|
||||
_this.classId=pathArr[pathArr.length-1].classId+'';
|
||||
_this.selectnodeid=pathArr[pathArr.length-1].id;
|
||||
_this.loadData();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取最后一级的map
|
||||
getFirstPath(rootNode) {
|
||||
const path = [];
|
||||
let cur = rootNode;
|
||||
while (cur) {
|
||||
// 存入当前层级关键信息
|
||||
path.push({
|
||||
id: cur.id,
|
||||
name: cur.name,
|
||||
type: cur.type,
|
||||
schsystemId:cur.schsystemId,
|
||||
gradeId:cur.gradeId,
|
||||
classId:cur.classId,
|
||||
});
|
||||
// 有子节点就取第一个,没有就终止
|
||||
if (cur.children && cur.children.length > 0) {
|
||||
cur = cur.children[0];
|
||||
} else {
|
||||
cur = null;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
},
|
||||
// 初始化表格列 配置式columns
|
||||
initTableColumn() {
|
||||
this.tableColumns = [
|
||||
{type: 'selection',width: 55,align: 'center'},
|
||||
{ title: '年级', key: 'gradeName', align: 'center' },
|
||||
{ title: '班级', key: 'className', align: 'center' },
|
||||
{ title: '姓名', key: 'name', align: 'center', width: 140 },
|
||||
{ title: '异动详情', key: 'abnormalStatusName', align: 'center' },
|
||||
{ title: '异动日期', key: 'className', align: 'center' },
|
||||
{ title: '身份证', key: 'idCard', align: 'center', width: 90 },
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
width: 80,
|
||||
render: (h, params) => {
|
||||
return h('Button', {
|
||||
props: { type: 'text', icon: 'md-create',type:'large' },
|
||||
on: { click: () => this.openEditModal(params.row) }
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// 树形选中切换
|
||||
treeLink(treeNode) {
|
||||
this.schsystemId=treeNode.schsystemId;
|
||||
this.gradeId=treeNode.gradeId?treeNode.gradeId+'':'';
|
||||
this.classId=treeNode.classId?treeNode.classId+'':'';
|
||||
this.selectnodeid=treeNode.id;
|
||||
this.pageNum = 1
|
||||
this.loadData()
|
||||
},
|
||||
|
||||
// 多选行回调
|
||||
selectionChange(rows) {
|
||||
this.selectedRows = rows
|
||||
},
|
||||
|
||||
// 加载列表数据
|
||||
loadData() {
|
||||
const _this = this;
|
||||
var item = {
|
||||
schsystemId:_this.schsystemId,
|
||||
gradeId:_this.gradeId,
|
||||
classId:_this.classId,
|
||||
keyword:_this.searchKey,
|
||||
page:_this.pageNum-1,
|
||||
size:_this.pageSize
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getbaseSchAbnormalSearch, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.tableData = resp.data.content;
|
||||
_this.total=resp.data.total;
|
||||
} else {
|
||||
_this.tableData = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.pageNum = 1;
|
||||
this.loadData();
|
||||
},
|
||||
|
||||
// 分页切换
|
||||
pageChange(p) {
|
||||
this.pageNum = p
|
||||
this.loadData()
|
||||
},
|
||||
sizeChange(size) {
|
||||
this.pageSize = size
|
||||
this.pageNum = 1
|
||||
this.loadData()
|
||||
},
|
||||
//学生编辑状态
|
||||
openEditModal(row) {
|
||||
this.changeStatusModalVisible=true;
|
||||
this.currentStuName=row.name;
|
||||
this.getstudentabnormal();
|
||||
this.selectedStatus=row.abnormalStatus;
|
||||
this.selectedRows=[row];
|
||||
},
|
||||
//还原事件
|
||||
submitChangeStatus() {
|
||||
if (!this.selectedRows.length) return this.$Message.warning('请勾选学生');
|
||||
const newItem = {
|
||||
abnormalStatus: 1,
|
||||
stuIds:this.selectedRows.map(a=>a.id)
|
||||
}
|
||||
const url = APIConfig.BschClassSystem.studentsetAbnormalStatus;
|
||||
this.$api.post(url, JSON.stringify(newItem), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success('异动状态修改完成');
|
||||
this.changeStatusModalVisible = false;
|
||||
this.selectedRows = [];
|
||||
this.loadData();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.student-manage-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
box-sizing: border-box;
|
||||
padding: 12px;
|
||||
}
|
||||
/* 左侧树固定高度 */
|
||||
.left-tree-box {
|
||||
width: 260px;
|
||||
border: 1px solid #e6e6e6;
|
||||
overflow-y: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
/* 右侧整体弹性布局 */
|
||||
.right-main-box {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
/* 顶部栏 */
|
||||
.top-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 0;
|
||||
margin-bottom: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.btn-left-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
/* 表格自适应滚动容器 */
|
||||
.table-scroll-wrap {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
height: 100%;
|
||||
}
|
||||
/* 底部栏:分页固定底部 */
|
||||
.bottom-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.page-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
/* 调班、异动弹窗按钮排版 */
|
||||
.class-btn-wrap, .status-btn-wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,341 @@
|
||||
<template>
|
||||
<div class="student-manage-wrap">
|
||||
<!-- 左侧树形区域 固定高度滚动 -->
|
||||
<div class="left-tree-box">
|
||||
<my-tree :treeData="treeData" :selectId="selectnodeid" @on-tree-click="treeLink"></my-tree>
|
||||
</div>
|
||||
|
||||
<!-- 右侧主体区域 -->
|
||||
<div class="right-main-box">
|
||||
<!-- 顶部按钮+搜索栏 -->
|
||||
<div class="top-bar">
|
||||
<div class="btn-left-group"></div>
|
||||
<div class="search-wrap" style="width: 100%;text-align: right;">
|
||||
<Input
|
||||
v-model="searchKey"
|
||||
placeholder="请输入学生姓名"
|
||||
search
|
||||
style="width:300px"
|
||||
@on-search="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格容器:自适应剩余高度滚动 -->
|
||||
<div class="table-scroll-wrap">
|
||||
<Table
|
||||
border
|
||||
stripe
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
:height="useTableHeight()-12"
|
||||
@on-selection-change="selectionChange"
|
||||
></Table>
|
||||
</div>
|
||||
|
||||
<!-- 左下角批量删除 + 底部分页固定 -->
|
||||
<div class="bottom-bar">
|
||||
<Button type="default" @click="selectedStatus=1;submitChangeStatus()">还原</Button>
|
||||
<div class="page-right">
|
||||
<span style="margin-right:12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,40,50]"
|
||||
show-sizer
|
||||
@on-change="pageChange"
|
||||
@on-page-size-change="sizeChange"
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗6:学生异动 -->
|
||||
<Modal v-model="changeStatusModalVisible" title="学生异动" width="520">
|
||||
<div style="padding:10px 0;">
|
||||
<div style="margin-bottom:16px;display:flex;align-items:center;">
|
||||
<span style="width:90px;">当前学生</span>
|
||||
<Input v-model="currentStuName" disabled style="flex:1;"></Input>
|
||||
</div>
|
||||
<div>
|
||||
<span style="width:90px;display:inline-block;margin-bottom:10px;">异动情况</span>
|
||||
<div class="status-btn-wrap">
|
||||
<Button
|
||||
v-for="item in studentabnormallist"
|
||||
:key="item.id"
|
||||
:type="selectedStatus===item.id?'primary':'default'"
|
||||
style="margin:6px"
|
||||
@click="selectedStatus=item.id"
|
||||
size="small"
|
||||
>{{ item.name }}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="changeStatusModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitChangeStatus()">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myTree from "../../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: 'StudentManage',
|
||||
components: { myTree },
|
||||
data() {
|
||||
return {
|
||||
// 左侧树形数据
|
||||
treeData: [],
|
||||
selectnodeid:'',
|
||||
enrollYear:'',
|
||||
classId:'',
|
||||
|
||||
// 搜索
|
||||
searchKey: '',
|
||||
|
||||
// 分页
|
||||
pageNum: 1,
|
||||
pageSize: 40,
|
||||
total: 0,
|
||||
selectedRows: [],
|
||||
|
||||
// 表格列配置
|
||||
tableColumns: [],
|
||||
tableData: [],
|
||||
|
||||
// 弹窗开关
|
||||
changeStatusModalVisible: false,
|
||||
|
||||
// 异动弹窗
|
||||
currentStuName: '',
|
||||
selectedStatus: null,
|
||||
studentabnormallist: [],
|
||||
}
|
||||
},
|
||||
mixins: [self_viewport],
|
||||
created() {
|
||||
this.getClassTree();
|
||||
this.initTableColumn()
|
||||
},
|
||||
methods: {
|
||||
//获取学生状态列表
|
||||
getstudentabnormal:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getstudentabnormal, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.studentabnormallist=resp.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取班级树
|
||||
getClassTree:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getHigherSchClassTree, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.treeData=resp.data;
|
||||
if(resp.data.children.length>0){
|
||||
// 起始节点为 data
|
||||
const pathArr = _this.getFirstPath(resp.data);
|
||||
_this.enrollYear=pathArr[pathArr.length-1].enrollYear+'',
|
||||
_this.classId=pathArr[pathArr.length-1].classId;
|
||||
_this.selectnodeid=pathArr[pathArr.length-1].id;
|
||||
_this.loadData();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取最后一级的map
|
||||
getFirstPath(rootNode) {
|
||||
const path = [];
|
||||
let cur = rootNode;
|
||||
while (cur) {
|
||||
// 存入当前层级关键信息
|
||||
path.push({
|
||||
id: cur.id,
|
||||
name: cur.name,
|
||||
type: cur.type,
|
||||
enrollYear:cur.enrollYear,
|
||||
classId:cur.classId
|
||||
});
|
||||
// 有子节点就取第一个,没有就终止
|
||||
if (cur.children && cur.children.length > 0) {
|
||||
cur = cur.children[0];
|
||||
} else {
|
||||
cur = null;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
},
|
||||
// 初始化表格列 配置式columns
|
||||
initTableColumn() {
|
||||
this.tableColumns = [
|
||||
{type: 'selection',width: 55,align: 'center'},
|
||||
{ title: '年级', key: 'gradeName', align: 'center' },
|
||||
{ title: '班级', key: 'className', align: 'center' },
|
||||
{ title: '姓名', key: 'name', align: 'center', width: 140 },
|
||||
{ title: '异动详情', key: 'abnormalStatusName', align: 'center' },
|
||||
{ title: '异动日期', key: 'className', align: 'center' },
|
||||
{ title: '身份证', key: 'idCard', align: 'center', width: 90 },
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
width: 80,
|
||||
render: (h, params) => {
|
||||
return h('Button', {
|
||||
props: { type: 'text', icon: 'md-create',type:'large' },
|
||||
on: { click: () => this.openEditModal(params.row) }
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
// 树形选中切换
|
||||
treeLink(treeNode) {
|
||||
this.enrollYear=treeNode.enrollYear?treeNode.enrollYear+'':'';
|
||||
this.classId=treeNode.classId?treeNode.classId+'':'';
|
||||
this.selectnodeid=treeNode.id;
|
||||
this.pageNum = 1
|
||||
this.loadData()
|
||||
},
|
||||
// 多选行回调
|
||||
selectionChange(rows) {
|
||||
this.selectedRows = rows
|
||||
},
|
||||
|
||||
// 加载列表数据
|
||||
loadData() {
|
||||
const _this = this;
|
||||
var item = {
|
||||
year:_this.enrollYear,
|
||||
classId:_this.classId,
|
||||
keyword:_this.keyword,
|
||||
page:_this.pageNum-1,
|
||||
size:_this.pageSize
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.gethigherSchAbnormalSearch, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.tableData = resp.data.content;
|
||||
_this.total=resp.data.total;
|
||||
} else {
|
||||
_this.tableData = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.pageNum = 1
|
||||
this.loadData()
|
||||
},
|
||||
|
||||
// 分页切换
|
||||
pageChange(p) {
|
||||
this.pageNum = p
|
||||
this.loadData()
|
||||
},
|
||||
sizeChange(size) {
|
||||
this.pageSize = size
|
||||
this.pageNum = 1
|
||||
this.loadData()
|
||||
},
|
||||
|
||||
//学生编辑状态
|
||||
openEditModal(row) {
|
||||
this.changeStatusModalVisible=true;
|
||||
this.currentStuName=row.name;
|
||||
this.getstudentabnormal();
|
||||
this.selectedStatus=row.abnormalStatus;
|
||||
this.selectedRows=[row];
|
||||
},
|
||||
//还原事件
|
||||
submitChangeStatus() {
|
||||
const newItem = {
|
||||
abnormalStatus: this.selectedStatus,
|
||||
stuIds:this.selectedRows.map(a=>a.id)
|
||||
}
|
||||
const url = APIConfig.BschClassSystem.studentsetAbnormalStatus;
|
||||
this.$api.post(url, JSON.stringify(newItem), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success('异动状态修改完成');
|
||||
this.changeStatusModalVisible = false;
|
||||
this.selectedRows = [];
|
||||
this.loadData();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.student-manage-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
box-sizing: border-box;
|
||||
padding: 12px;
|
||||
}
|
||||
/* 左侧树固定高度 */
|
||||
.left-tree-box {
|
||||
width: 260px;
|
||||
border: 1px solid #e6e6e6;
|
||||
overflow-y: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
/* 右侧整体弹性布局 */
|
||||
.right-main-box {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
/* 顶部栏 */
|
||||
.top-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 0;
|
||||
margin-bottom: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.btn-left-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
/* 表格自适应滚动容器 */
|
||||
.table-scroll-wrap {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
height: 100%;
|
||||
}
|
||||
/* 底部栏:分页固定底部 */
|
||||
.bottom-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.page-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
/* 调班、异动弹窗按钮排版 */
|
||||
.class-btn-wrap, .status-btn-wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,217 @@
|
||||
<template>
|
||||
<div class="edu-layout-wrap">
|
||||
<Row gutter="10" class="layout-row">
|
||||
<!-- 左侧:学校树形 -->
|
||||
<Col span="4" class="left-tree-wrap" style="overflow: auto;" :style="'height:'+(useTableHeight({ isSearch: true, isOperat: true })+160)+'px'">
|
||||
<div class="tree-title">学校</div>
|
||||
<my-tree :treeData="treeData" @on-tree-click="treeLink"></my-tree>
|
||||
</Col>
|
||||
|
||||
<!-- 右侧:学制选择 -->
|
||||
|
||||
<Col span="20" class="right-select-wrap" :style="'height:'+(useTableHeight({ isSearch: true, isOperat: true })+160)+'px'">
|
||||
<div class="select-title">学制选择</div>
|
||||
<!-- 幼儿园分组 -->
|
||||
<div class="group-wrap" v-for="(itt,index) in schsystemlist" :key="index">
|
||||
<div class="group-label">{{ itt.academicStageName }}</div>
|
||||
<div class="btn-group-row">
|
||||
<Button
|
||||
v-for="(item,index2) in itt.academicStageList"
|
||||
:key="item.id"
|
||||
:type="item.checked ? 'primary' : 'default'"
|
||||
shape="circle"
|
||||
@click="selectEduType(item.id,index,index2)"
|
||||
class="edu-btn"
|
||||
>
|
||||
{{ item.name }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-bottom:20px;"></div>
|
||||
<!-- 底部确定按钮 -->
|
||||
<div class="confirm-btn-wrap" style="position: fixed;bottom: 0;text-align: center;left: 0;right: 0;background: #fff;padding: 10px;border-top: 1px solid #eee;">
|
||||
<Button type="primary" style="padding:0px 40px;" @click="handleConfirm">确定</Button>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myTree from "../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: "EduYearSelect",
|
||||
components: { myTree},
|
||||
data() {
|
||||
return {
|
||||
selectedEdu: "",
|
||||
selectedSchool: null,
|
||||
treeData: [],
|
||||
schsystemlist:[],
|
||||
selectnodeid:0
|
||||
};
|
||||
|
||||
},
|
||||
mixins: [self_viewport],
|
||||
created(){
|
||||
let _this=this;
|
||||
_this.getGroupTree();
|
||||
_this.getschsystemlist();
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
//获取全区树
|
||||
getGroupTree:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getGroupTree, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.treeData = resp.data;
|
||||
}else{
|
||||
_this.treeData=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
//节点点击事件
|
||||
treeLink(treeNode){
|
||||
if(treeNode.type==2){
|
||||
this.selectnodeid=treeNode.id;
|
||||
this.getschsystemlist();
|
||||
}
|
||||
},
|
||||
//获取学校绑定学制列表
|
||||
getschsystemlist:function(){
|
||||
const _this = this;
|
||||
var item={
|
||||
schId:this.selectnodeid
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getschsystemlist, item, resp => {
|
||||
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.schsystemlist = resp.data;
|
||||
}else{
|
||||
_this.schsystemlist=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
selectEduType(val,index,index2) {
|
||||
const list = this.schsystemlist[index].academicStageList;
|
||||
// 先记录当前点击项原本的勾选状态
|
||||
const originChecked = list[index2].checked;
|
||||
// 本组全部取消选中
|
||||
list.forEach(item => {
|
||||
item.checked = false;
|
||||
});
|
||||
// 如果原来没选中 → 选中;原来已选中 → 保持取消
|
||||
if (!originChecked) {
|
||||
list[index2].checked = true;
|
||||
}
|
||||
},
|
||||
handleConfirm() {
|
||||
if (!this.selectnodeid) {
|
||||
this.$Message.warning("请先选择左侧学校");
|
||||
return;
|
||||
}
|
||||
const checkedIdArr = this.schsystemlist
|
||||
.flatMap(item => item.academicStageList)
|
||||
.filter(item => item.checked)
|
||||
.map(item => item.id);
|
||||
if (checkedIdArr.length==0) {
|
||||
this.$Message.warning("请选择对应学制");
|
||||
return;
|
||||
}
|
||||
const submitData = {
|
||||
schId: this.selectnodeid,
|
||||
schsystemIds: checkedIdArr.join(',')
|
||||
};
|
||||
var url = APIConfig.BschClassSystem.schsystemsave;
|
||||
this.$api.post(url, submitData, resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("已设置完成!");
|
||||
this.getschsystemlist();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.edu-layout-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
background: #fff;
|
||||
}
|
||||
.layout-row {
|
||||
height: 100%;
|
||||
}
|
||||
.left-tree-wrap {
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
border-top-right-radius: 0;
|
||||
/* height: 650px; */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.tree-title {
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
padding: 10px 10px 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.edu-tree {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.right-select-wrap {
|
||||
border: 1px solid #e5e7eb;
|
||||
border-left: 0px;
|
||||
border-radius: 4px;
|
||||
border-top-left-radius: 0;
|
||||
/* height: 650px; */
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
}
|
||||
.select-title {
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.group-wrap {
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
.group-label {
|
||||
font-size: 18px;
|
||||
padding: 12px 10px;
|
||||
background-color: #f5f5f5;
|
||||
margin-bottom: 15px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.btn-group-row {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
.edu-btn {
|
||||
padding: 6px 22px;
|
||||
font-size: 15px;
|
||||
}
|
||||
.confirm-btn-wrap {
|
||||
margin-top: auto;
|
||||
text-align: center;
|
||||
padding-top: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,443 @@
|
||||
<template>
|
||||
<!-- 最外层整体边框容器(和校区/系部/专业页面统一外壳样式) -->
|
||||
<div class="outer-wrap">
|
||||
<!-- 顶部筛选+操作栏 -->
|
||||
<div class="top-bar">
|
||||
<Button type="primary" icon="ios-add" @click="openAddModal">添加课程</Button>
|
||||
<div class="filter-group">
|
||||
<Select v-model="filterDept" placeholder="选择所属系部" style="width:160px;margin-right:10px" @on-change="handleSearch" clearable>
|
||||
<Option v-for="item in divisionselectlist" :key="item.id" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
<Select v-model="filterMajor" placeholder="选择所属专业" style="width:180px;margin-right:10px" @on-change="handleSearch" clearable filterable>
|
||||
<Option v-for="item in majorsselectlist" :key="item.id" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
<Select v-model="filterType" placeholder="选择类型" style="width:140px;margin-right:10px" @on-change="handleSearch" clearable>
|
||||
<Option v-for="item in coursetypeselectlist" :key="item.id" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
<Input
|
||||
v-model="keyword"
|
||||
placeholder="输入代码或名称搜索"
|
||||
style="width:240px"
|
||||
@keyup.enter="handleSearch"
|
||||
>
|
||||
<Icon slot="suffix" type="ios-search" @click="handleSearch" style="cursor:pointer;"></Icon>
|
||||
</Input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自适应表格区域:内容滚动、分页固定底部 -->
|
||||
<div class="adapt-container">
|
||||
<!-- 表格滚动容器 -->
|
||||
<div class="table-scroll-box">
|
||||
<Table
|
||||
border
|
||||
stripe
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
class="course-table"
|
||||
></Table>
|
||||
</div>
|
||||
|
||||
<!-- 底部分页固定 -->
|
||||
<div class="pagination-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>
|
||||
|
||||
<!-- 新增/编辑课程弹窗(匹配编辑课程信息截图) -->
|
||||
<Modal v-model="modalVisible" :title="modalTitle" width="580">
|
||||
<Form ref="form" :model="formData" :rules="formRules" label-width="110">
|
||||
<FormItem label="课程代码" prop="courseCode">
|
||||
<Input v-model="formData.courseCode" placeholder="请输入课程代码"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="课程名称" prop="courseName">
|
||||
<Input v-model="formData.courseName" placeholder="请输入课程名称"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="课程类别" prop="courseType">
|
||||
<Select v-model="formData.courseType" placeholder="请选择类别" style="width:100%" transfer>
|
||||
<Option v-for="item in coursetypeselectlist" :key="item.id" :value="item.id+''">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="所属专业" prop="bindMajor">
|
||||
<Select
|
||||
v-model="formData.bindMajor"
|
||||
multiple
|
||||
placeholder="可多选所属专业"
|
||||
style="width:100%" transfer
|
||||
>
|
||||
<Option v-for="(item,index) in majorsselectlist" :key="index" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="课程系部" prop="bindDept">
|
||||
<Select
|
||||
v-model="formData.bindDept"
|
||||
multiple
|
||||
placeholder="可多选所属系部"
|
||||
style="width:100%" transfer
|
||||
>
|
||||
<Option v-for="(item,index) in divisionselectlist" :key="index" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="modalVisible = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitForm">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'CourseManage',
|
||||
data() {
|
||||
return {
|
||||
// 顶部筛选条件
|
||||
keyword: '',
|
||||
filterDept: '',
|
||||
filterMajor: '',
|
||||
filterType: '',
|
||||
|
||||
// 分页参数 iView2 Page 配置
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
|
||||
// 下拉选项数据源
|
||||
divisionselectlist: [],
|
||||
majorsselectlist: [],
|
||||
coursetypeselectlist:[],
|
||||
// iView2 表格列配置(摒弃TableColumn,columns标准写法)
|
||||
tableColumns: [
|
||||
{ title: '序号', type: 'index', align: 'center', width: 70 },
|
||||
{ title: '课程代码', key: 'code', align: 'center' },
|
||||
{ title: '课程名称', key: 'name', align: 'center' },
|
||||
{ title: '类型', key: 'typeName', align: 'center' },
|
||||
{
|
||||
title: '所属专业',
|
||||
key: 'bindMajorStr',
|
||||
align: 'center',
|
||||
render: (h, params) => {
|
||||
var ZGZList = params.row.majorsList;//数据数组
|
||||
var newArr = [];
|
||||
ZGZList.forEach((a,index)=>{
|
||||
newArr.push(h('div',{class:'spcontent'},[
|
||||
h('span', a.name)
|
||||
]))
|
||||
})
|
||||
return h('div',newArr);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '所属系部',
|
||||
key: 'bindDeptStr',
|
||||
align: 'center',
|
||||
render: (h, params) => {
|
||||
var ZGZList = params.row.divisionList;//数据数组
|
||||
var newArr = [];
|
||||
ZGZList.forEach((a,index)=>{
|
||||
newArr.push(h('div',{class:'spcontent'},[
|
||||
h('span', a.name)
|
||||
]))
|
||||
})
|
||||
return h('div',newArr);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
width: 120,
|
||||
render: (h, params) => {
|
||||
return h('div', { style: 'display:flex;gap:12px;justify-content:center' }, [
|
||||
h('Button', {
|
||||
props: { type: 'text', icon: 'ios-create', size: 'default' },
|
||||
on: { click: () => this.editRow(params.row, params.index) }
|
||||
}),
|
||||
h('Button', {
|
||||
props: { type: 'text', icon: 'ios-trash', size: 'default' },
|
||||
on: { click: () => this.delRow(params.index) }
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
// 表格模拟数据(和截图内容一一对应)
|
||||
tableData: [],
|
||||
|
||||
// 弹窗控制
|
||||
modalVisible: false,
|
||||
modalTitle: '',
|
||||
editIndex: null,
|
||||
// 表单数据(匹配编辑弹窗5个字段)
|
||||
formData: {
|
||||
courseCode: '',
|
||||
courseName: '',
|
||||
courseType: '',
|
||||
bindMajor: [],
|
||||
bindDept: []
|
||||
},
|
||||
// 表单校验规则
|
||||
formRules: {
|
||||
courseCode: [{ required: true, message: '请输入课程代码', trigger: 'blur' }],
|
||||
courseName: [{ required: true, message: '请输入课程名称', trigger: 'blur' }],
|
||||
courseType: [{ required: true, message: '请选择课程类别', trigger: 'change' }],
|
||||
bindMajor: [{ required: true, type: 'array', min: 1, message: '请选择所属专业', trigger: 'change' }],
|
||||
bindDept:[{ required: true, type: 'array', min: 1, message: '请选择课程系部', trigger: 'change' }],
|
||||
}
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.getdivisionselect();
|
||||
this.getmajorsselect();
|
||||
this.getcoursetypeselect();
|
||||
this.getcourselist();
|
||||
},
|
||||
methods: {
|
||||
//系部下拉
|
||||
getdivisionselect() {
|
||||
const _this = this;
|
||||
var item = {};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getdivisionselect, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.divisionselectlist = resp.data;
|
||||
} else {
|
||||
_this.divisionselectlist = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
//专业下拉
|
||||
getmajorsselect() {
|
||||
const _this = this;
|
||||
var item = {};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getmajorsselect, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.majorsselectlist = resp.data;
|
||||
} else {
|
||||
_this.majorsselectlist = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
//课程类别下拉
|
||||
getcoursetypeselect() {
|
||||
const _this = this;
|
||||
var item = {};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getcoursetypeselect, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.coursetypeselectlist = resp.data;
|
||||
} else {
|
||||
_this.coursetypeselectlist = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取课程列表
|
||||
getcourselist() {
|
||||
const _this = this;
|
||||
var item = {
|
||||
keyword: this.keyword,
|
||||
divisionId: this.filterDept,
|
||||
majorsId: this.filterMajor,
|
||||
type: this.filterType,
|
||||
page:this.pageNum-1,
|
||||
size:this.pageSize,
|
||||
sort:'id'
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getcourselist, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.tableData = resp.data.content;
|
||||
_this.total=resp.data.total;
|
||||
} else {
|
||||
_this.tableData = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
// 搜索重置页码
|
||||
handleSearch() {
|
||||
this.pageNum = 1
|
||||
this.getcourselist();
|
||||
},
|
||||
// 页码切换
|
||||
pageChange(page) {
|
||||
this.pageNum = page;
|
||||
this.getcourselist();
|
||||
},
|
||||
// 每页条数修改
|
||||
sizeChange(size) {
|
||||
this.pageSize = size;
|
||||
this.pageNum = 1;
|
||||
this.getcourselist();
|
||||
},
|
||||
|
||||
// 打开新增弹窗
|
||||
openAddModal() {
|
||||
this.editIndex = null
|
||||
this.modalTitle = '新增课程信息'
|
||||
this.formData = {
|
||||
courseCode: '',
|
||||
courseName: '',
|
||||
courseType: '',
|
||||
bindMajor: [],
|
||||
bindDept: []
|
||||
}
|
||||
this.modalVisible = true
|
||||
},
|
||||
|
||||
// 编辑行回填弹窗
|
||||
editRow(row, idx) {
|
||||
this.editIndex = idx
|
||||
this.modalTitle = '编辑课程信息'
|
||||
this.formData = {
|
||||
id:row.id,
|
||||
courseCode: row.code,
|
||||
courseName: row.name,
|
||||
courseType: row.type+'',
|
||||
bindMajor: row.majorsList.map(a=>a.id),
|
||||
bindDept: row.divisionList.map(a=>a.id)
|
||||
}
|
||||
this.modalVisible = true
|
||||
},
|
||||
|
||||
// 删除弹窗确认
|
||||
delRow(idx) {
|
||||
this.$Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定删除当前课程?',
|
||||
onOk: () => {
|
||||
var url=APIConfig.BschClassSystem.coursedelete+this.tableData[idx].id;
|
||||
this.$api.post(url,{},(resp)=>{
|
||||
this.$Message.success('删除成功!');
|
||||
this.getcourselist();
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 弹窗提交
|
||||
submitForm() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (!valid) return
|
||||
const form = this.formData
|
||||
if (this.editIndex === null) {
|
||||
// 新增
|
||||
const newItem = {
|
||||
code: form.courseCode,
|
||||
name: form.courseName,
|
||||
type: form.courseType,
|
||||
majorsIds: form.bindMajor,
|
||||
divisionIds:form.bindDept
|
||||
}
|
||||
const url = APIConfig.BschClassSystem.coursesave;
|
||||
this.$api.post(url, JSON.stringify(newItem), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("新增课程成功!");
|
||||
this.getcourselist();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 编辑修改
|
||||
const newItem = {
|
||||
id:form.id,
|
||||
code: form.courseCode,
|
||||
name: form.courseName,
|
||||
type: form.courseType,
|
||||
majorsIds: form.bindMajor,
|
||||
divisionIds:form.bindDept
|
||||
}
|
||||
const url = APIConfig.BschClassSystem.coursesave;
|
||||
this.$api.post(url, JSON.stringify(newItem), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("编辑课程成功!");
|
||||
this.getcourselist();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.modalVisible = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 全局外边框,和之前校区/系部/专业页面样式统一 */
|
||||
.outer-wrap {
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
/* margin:0 10px; */
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 顶部操作筛选栏 */
|
||||
.top-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
background: #f7f7f7;
|
||||
margin-bottom: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.filter-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 自适应主体容器 */
|
||||
.adapt-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
/* 表格区域自动填充剩余高度,内部滚动 */
|
||||
.table-scroll-box {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.course-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 分页固定底部,不跟随表格滚动 */
|
||||
.pagination-bottom {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.total-text {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.spcontent{
|
||||
border: 1px solid #dcdee2;
|
||||
border-radius: 5px;
|
||||
padding: 2px 5px;
|
||||
background: #f8f8f9;
|
||||
margin: 5px 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,372 @@
|
||||
<template>
|
||||
<div class="outer-wrap">
|
||||
<!-- 顶部年级下拉 -->
|
||||
<div class="top-select-wrap">
|
||||
<Select v-model="gradeVal" style="width:140px" @on-change="getsubjectlist">
|
||||
<Option v-for="(item,index) in schsystemselectlist" :key="index" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<!-- 所有学科拖拽容器(两类混排) -->
|
||||
<div class="subject-box">
|
||||
<div class="btn-container">
|
||||
<draggable
|
||||
v-model="subjectlist"
|
||||
class="drag-wrap"
|
||||
animation="200"
|
||||
:options="{ group: 'people' }"
|
||||
@start="drag = true"
|
||||
@end="drag = false"
|
||||
:move="getdata1"
|
||||
@update="datadragEnd1"
|
||||
>
|
||||
<div
|
||||
v-for="(item, idx) in subjectlist"
|
||||
:key="idx"
|
||||
class="subject-btn"
|
||||
:class="[item.source === 0 ? 'sys-btn' : 'cus-btn', { active: item.enable }]"
|
||||
@click="toggleSelect(idx)"
|
||||
@mouseenter="item.source === 1 && (hoverIndex = idx)"
|
||||
@mouseleave="hoverIndex = null"
|
||||
>
|
||||
<span class="text">{{ item.name }}</span>
|
||||
<!-- 仅自建学科悬浮显示编辑删除 -->
|
||||
<div v-if="item.source === 1 && hoverIndex === idx" class="operate-group" @click.stop>
|
||||
<span class="icon-edit" @click="editItem(idx)">✏️</span>
|
||||
<span class="icon-del" @click="delItem(idx)">🗑️</span>
|
||||
</div>
|
||||
</div>
|
||||
</draggable>
|
||||
<!-- 添加自建学科按钮 -->
|
||||
<Button icon="ios-add-outline" class="add-subject-btn" size="large" @click="openAddModal">
|
||||
添加学科
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部图例说明 -->
|
||||
<div class="legend-bottom">
|
||||
<span class="legend-item">
|
||||
<i class="legend-box system-box"></i>
|
||||
系统学科(蓝色,可多选、拖拽排序,不可删改)
|
||||
</span>
|
||||
<span class="legend-item">
|
||||
<i class="legend-box custom-box"></i>
|
||||
学校自建学科(绿色,可多选、拖拽、hover编辑删除)
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑弹窗 学科信息 -->
|
||||
<Modal v-model="modalVisible" title="学科信息" width="420">
|
||||
<Form ref="form" :model="formData" :rules="formRules" label-width="90">
|
||||
<FormItem label="学科名称" prop="subjectName">
|
||||
<Input v-model="formData.subjectName" placeholder="请输入学科名称"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="modalVisible = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitForm">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
export default {
|
||||
name: 'SubjectManage',
|
||||
components: { draggable },
|
||||
data() {
|
||||
return {
|
||||
schsystemselectlist:[],
|
||||
gradeVal: '',
|
||||
hoverIndex: null,
|
||||
// 选中下标数组,支持多选
|
||||
selectedIndexArr: [],
|
||||
|
||||
// 合并数组:type区分 system系统 / custom自建
|
||||
subjectlist: [],
|
||||
|
||||
modalVisible: false,
|
||||
editIndex: null,
|
||||
formData: {id:0,subjectName: '',enable:true,source:1,sort:null },
|
||||
formRules: {
|
||||
subjectName: [{ required: true, message: '请输入学科名称', trigger: 'blur' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.getschsystemselect();
|
||||
},
|
||||
methods: {
|
||||
//学制下拉
|
||||
getschsystemselect() {
|
||||
const _this = this;
|
||||
var item = {};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getschsystemselect, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.schsystemselectlist = resp.data;
|
||||
if(_this.schsystemselectlist.length>0){
|
||||
_this.gradeVal=_this.schsystemselectlist[0].id;
|
||||
_this.getsubjectlist();
|
||||
}
|
||||
} else {
|
||||
_this.schsystemselectlist = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取学科列表
|
||||
getsubjectlist() {
|
||||
const _this = this;
|
||||
var item = {
|
||||
schSystemId:_this.gradeVal
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getsubjectlist, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.subjectlist = resp.data;
|
||||
} else {
|
||||
_this.subjectlist = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
// 多选切换选中/取消
|
||||
toggleSelect(index) {
|
||||
let submap=this.subjectlist[index];
|
||||
this.$set(this.subjectlist[index], 'enable', !submap.enable);
|
||||
const submitData ={
|
||||
id:submap.id,
|
||||
name:submap.name,
|
||||
schSystemId:this.gradeVal,
|
||||
enable:submap.enable,
|
||||
source:submap.source,
|
||||
sort:submap.sort
|
||||
};
|
||||
const url = APIConfig.BschClassSystem.subjectsave;
|
||||
this.$api.post(url, JSON.stringify(submitData), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("启用成功!");
|
||||
this.getsubjectlist();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
//学科拖动前
|
||||
getdata1 (evt) {
|
||||
//console.log(evt.draggedContext.element)
|
||||
},
|
||||
|
||||
//学科拖动后
|
||||
datadragEnd1 (evt) {
|
||||
var _this=this;
|
||||
//console.log('拖动后的索引 :' + evt.newIndex);
|
||||
//console.log('拖动前的索引 :' + evt.oldIndex);
|
||||
var ids=[],orders=[];
|
||||
_this.subjectlist.forEach(element => {
|
||||
ids.push(element.code);
|
||||
});
|
||||
var url=APIConfig.BschClassSystem.subjectsort+'?schSystemId='+_this.gradeVal;
|
||||
_this.$api.post(url,JSON.stringify(ids),(resp)=>{
|
||||
_this.$Message.info('拖动排序成功!');
|
||||
_this.getsubjectlist();
|
||||
});
|
||||
},
|
||||
// 打开新增(默认新增自建学科)
|
||||
openAddModal() {
|
||||
this.editIndex = null
|
||||
this.formData.subjectName = ''
|
||||
this.modalVisible = true
|
||||
},
|
||||
|
||||
// 编辑自建学科
|
||||
editItem(index) {
|
||||
const row = this.subjectlist[index]
|
||||
if (row.source !== 1) return
|
||||
this.editIndex = index
|
||||
this.formData.subjectName = row.name;
|
||||
this.formData.id=row.id;
|
||||
this.formData.enable=row.enable;
|
||||
this.formData.sort=row.sort;
|
||||
this.modalVisible = true
|
||||
},
|
||||
|
||||
// 删除自建学科
|
||||
delItem(index) {
|
||||
const row = this.subjectlist[index]
|
||||
if (row.source !== 1) return
|
||||
this.$Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定删除该学科?',
|
||||
onOk: () => {
|
||||
// 删除条目
|
||||
var url=APIConfig.BschClassSystem.subjectdelete+this.subjectlist[index].id;
|
||||
this.$api.post(url,{},(resp)=>{
|
||||
this.$Message.success('删除成功!');
|
||||
this.getsubjectlist();
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 弹窗提交
|
||||
submitForm() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (!valid) return
|
||||
const name = this.formData.subjectName.trim()
|
||||
if (this.editIndex === null) {
|
||||
// 新增默认是自建学科
|
||||
const submitData ={
|
||||
name:name,
|
||||
schSystemId:this.gradeVal,
|
||||
enable:true,
|
||||
source:1,
|
||||
sort:null
|
||||
};
|
||||
const url = APIConfig.BschClassSystem.subjectsave;
|
||||
this.$api.post(url, JSON.stringify(submitData), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("新增自建学科成功!");
|
||||
this.getsubjectlist();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 修改原有自建学科名称
|
||||
const submitData ={
|
||||
id:this.formData.id,
|
||||
name:name,
|
||||
schSystemId:this.gradeVal,
|
||||
enable:this.formData.enable,
|
||||
source:this.formData.source,
|
||||
sort:this.formData.sort
|
||||
};
|
||||
const url = APIConfig.BschClassSystem.subjectsave;
|
||||
this.$api.post(url, JSON.stringify(submitData), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success("修改学科成功!");
|
||||
this.getsubjectlist();
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.modalVisible = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.outer-wrap {
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.top-select-wrap {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.subject-box {
|
||||
flex: 1;
|
||||
}
|
||||
.btn-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
row-gap: 16px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.drag-wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
row-gap: 16px;
|
||||
}
|
||||
|
||||
/* 按钮基础通用样式 */
|
||||
.subject-btn {
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* ========== 系统学科 蓝色样式 ========== */
|
||||
.sys-btn {
|
||||
border: 1px solid #4080ff;
|
||||
color: #4080ff;
|
||||
background: #fff;
|
||||
}
|
||||
.sys-btn.active {
|
||||
background: #4080ff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* ========== 自建学科 绿色样式 ========== */
|
||||
.cus-btn {
|
||||
border: 1px solid #00b42a;
|
||||
color: #00b42a;
|
||||
background: #fff;
|
||||
}
|
||||
.cus-btn.active {
|
||||
background: #00b42a;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* 悬浮编辑删除组 */
|
||||
.operate-group {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
}
|
||||
.icon-edit, .icon-del {
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.add-subject-btn {
|
||||
padding: 8px 16px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.legend-bottom {
|
||||
margin-top: 30px;
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
align-items: center;
|
||||
}
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
.legend-box {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 3px;
|
||||
display: inline-block;
|
||||
}
|
||||
.system-box {
|
||||
border: 1px solid #4080ff;
|
||||
background: #fff;
|
||||
}
|
||||
.custom-box {
|
||||
border: 1px solid #00b42a;
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div class="outer-wrap" style="height:calc(100% - 50px);">
|
||||
<!-- 顶部标签切换 -->
|
||||
<Tabs v-model="activeTab" type="line">
|
||||
<TabPane label="教师信息管理" :name="1"></TabPane>
|
||||
<TabPane label="任教管理" :name="2"></TabPane>
|
||||
<TabPane label="教师分组管理" :name="3"></TabPane>
|
||||
<!-- <TabPane label="教师变动查询" :name="4"></TabPane> -->
|
||||
</Tabs>
|
||||
<teacherinfo v-if="activeTab==1"></teacherinfo>
|
||||
<teachseeting v-if="activeTab==2"></teachseeting>
|
||||
<Teachergrouping v-if="activeTab==3"></Teachergrouping>
|
||||
<Teachertransfer v-if="activeTab==4"></Teachertransfer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import teacherinfo from "./teacherManage/teacherinfo";
|
||||
import teachseeting from "./teacherManage/teachseeting";
|
||||
import Teachergrouping from "./teacherManage/Teachergrouping";
|
||||
import Teachertransfer from "./teacherManage/Teachertransfer";
|
||||
export default {
|
||||
name: 'teacherManage',
|
||||
components: { teacherinfo,teachseeting,Teachergrouping,Teachertransfer },
|
||||
data() {
|
||||
return {
|
||||
activeTab:1,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,302 @@
|
||||
<template>
|
||||
<div class="teacher-transfer-wrap">
|
||||
<!-- 顶部筛选栏 -->
|
||||
<div class="top-filter-bar">
|
||||
<div class="search-wrap" style="width:100%;">
|
||||
<span>学校:</span>
|
||||
<Select v-model="filterSchool" style="width: 180px" @on-change="getgroupSelectBySchId">
|
||||
<Option value="-1">全部</Option>
|
||||
<Option v-for="item in SchoolList" :key="item.id" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
<span style="margin-left: 16px">学科组:</span>
|
||||
<Select v-model="filterGroup" style="width: 180px" @on-change="handleFilterChange">
|
||||
<Option value="-1">全部</Option>
|
||||
<Option v-for="item in groupSelectBySchIdlList" :key="item.id" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
<span class="fr">
|
||||
<Input
|
||||
placeholder="请输入教师姓名"
|
||||
search
|
||||
@on-search="handleSearch"
|
||||
suffix="ios-search"
|
||||
style="width: 280px"
|
||||
v-model="searchName"
|
||||
/>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自适应滚动表格容器 -->
|
||||
<div class="table-scroll-wrap">
|
||||
<Table
|
||||
border
|
||||
stripe
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
:height="useTableHeight()+32"
|
||||
@on-selection-change="onSelectChange"
|
||||
></Table>
|
||||
</div>
|
||||
|
||||
<!-- 底部栏:转入按钮 + 固定分页 -->
|
||||
<div class="bottom-bar">
|
||||
<Button type="default" status="danger" @click="openTransferModal">转入</Button>
|
||||
<div class="page-area">
|
||||
<span style="margin-right: 12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,40]"
|
||||
show-sizer
|
||||
@on-change="pageChange"
|
||||
@on-page-size-change="sizeChange"
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗:转至其他组 -->
|
||||
<Modal v-model="transferModalVisible" title="转至其他组" width="540">
|
||||
<div style="padding: 15px 10px;">
|
||||
<div style="margin-bottom: 18px;display: flex;align-items: center;">
|
||||
<span style="width: 100px;">待移动教师:</span>
|
||||
<Input v-model="moveTeacherName" disabled style="flex:1;"></Input>
|
||||
</div>
|
||||
<div>
|
||||
<span style="width: 100px;display: inline-block;margin-bottom: 10px;color:#f56c6c;font-weight:bold;">移动至:</span>
|
||||
<my-tree :treeData="groupTreeData" @on-tree-click="treeLink"></my-tree>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="transferModalVisible = false">取消</Button>
|
||||
<Button type="primary" @click="submitTransfer">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myTree from "../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: 'TeacherTransferPage',
|
||||
components: { myTree },
|
||||
data() {
|
||||
return {
|
||||
// 筛选条件
|
||||
filterSchool: '-1',
|
||||
filterGroup: '-1',
|
||||
searchName: '',
|
||||
|
||||
// 分页
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
selectedRows: [],
|
||||
|
||||
// 表格配置列
|
||||
tableColumns: [],
|
||||
SchoolList:[],
|
||||
groupSelectBySchIdlList:[],
|
||||
tableData: [],
|
||||
|
||||
// 转入弹窗
|
||||
transferModalVisible: false,
|
||||
selectnodeid:0,
|
||||
moveTeacherName: '',
|
||||
targetGroupNode: null,
|
||||
// 目标分组树形数据
|
||||
groupTreeData: []
|
||||
}
|
||||
},
|
||||
mixins: [self_viewport],
|
||||
created() {
|
||||
this.getSchoolList();
|
||||
this.initTableColumn()
|
||||
this.loadTableData()
|
||||
},
|
||||
methods: {
|
||||
//获取学校
|
||||
getSchoolList:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.transferOutSchSelect, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.SchoolList = resp.data;
|
||||
}else{
|
||||
_this.SchoolList=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取科室
|
||||
getgroupSelectBySchId:function(){
|
||||
const _this = this;
|
||||
var item={
|
||||
schId:_this.filterSchool
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getgroupSelectBySchId, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.groupSelectBySchIdlList = resp.data;
|
||||
}else{
|
||||
_this.groupSelectBySchIdlList=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
// 初始化配置式表格列
|
||||
initTableColumn() {
|
||||
this.tableColumns = [
|
||||
{ type: 'selection', width: 55, align: 'center' },
|
||||
{ title: '序号', type: 'index', align: 'center', width: 70 },
|
||||
{ title: '学校', key: 'schName', align: 'center' },
|
||||
{ title: '学科组', key: 'groupNames', align: 'center', width: 110 },
|
||||
{ title: '教师姓名', key: 'name', align: 'center' },
|
||||
{ title: '身份证', key: 'idCard', align: 'center' },
|
||||
]
|
||||
},
|
||||
|
||||
// 勾选行回调
|
||||
onSelectChange(rows) {
|
||||
this.selectedRows = rows
|
||||
},
|
||||
|
||||
// 加载列表数据
|
||||
loadTableData() {
|
||||
const _this = this;
|
||||
var item = {
|
||||
schId:_this.filterSchool=='-1'?'':_this.filterSchool,
|
||||
groupId:_this.filterGroup=='-1'?'':_this.filterGroup,
|
||||
keyword:_this.searchName,
|
||||
page:_this.pageNum-1,
|
||||
size:_this.pageSize
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getsearchTransferOut, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.tableData = resp.data.content;
|
||||
_this.total=resp.data.total;
|
||||
} else {
|
||||
_this.tableData = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 下拉筛选切换
|
||||
handleFilterChange() {
|
||||
this.pageNum = 1
|
||||
this.loadTableData()
|
||||
},
|
||||
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.pageNum = 1
|
||||
this.loadTableData()
|
||||
},
|
||||
|
||||
// 分页切换
|
||||
pageChange(p) {
|
||||
this.pageNum = p
|
||||
this.loadTableData()
|
||||
},
|
||||
sizeChange(size) {
|
||||
this.pageSize = size
|
||||
this.pageNum = 1
|
||||
this.loadTableData()
|
||||
},
|
||||
|
||||
// 打开转入弹窗
|
||||
openTransferModal() {
|
||||
if (!this.selectedRows.length) {
|
||||
return this.$Message.warning('请先勾选需要转入的教师')
|
||||
}
|
||||
this.moveTeacherName=this.selectedRows.map(a=>a.name).join(',');
|
||||
this.transferModalVisible = true
|
||||
this.getTeaTree();
|
||||
},
|
||||
//获取教师树
|
||||
getTeaTree:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getTeaTree, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.groupTreeData=resp.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
// 树形选中切换
|
||||
treeLink(treeNode) {
|
||||
this.selectnodeid=treeNode.id;
|
||||
},
|
||||
// 提交转入分组
|
||||
submitTransfer() {
|
||||
if (!this.selectnodeid) {
|
||||
return this.$Message.warning('请选择目标分组')
|
||||
}
|
||||
const teacherIdArr = this.selectedRows.map(row => row.schId+'_'+row.teaId);
|
||||
let item={
|
||||
schTeaIds:teacherIdArr,
|
||||
transferGroupId:this.selectnodeid
|
||||
};
|
||||
const url = APIConfig.BschClassSystem.setTransferIn;
|
||||
this.$api.post(url,JSON.stringify(item), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success('教师转入分组成功!');
|
||||
this.transferModalVisible = false
|
||||
this.selectedRows = []
|
||||
this.loadTableData()
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.teacher-transfer-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
/* 顶部筛选行 */
|
||||
.top-filter-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 14px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.filter-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 表格自适应滚动容器 */
|
||||
.table-scroll-wrap {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 底部栏:分页固定底部 */
|
||||
.bottom-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 14px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.page-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div style="height:100%;">
|
||||
<Christianity v-if="type==1"></Christianity>
|
||||
<HigherEducation v-if="type==2"></HigherEducation>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Christianity from "./zhuanruinfostu/Christianity";
|
||||
import HigherEducation from "./zhuanruinfostu/HigherEducation";
|
||||
export default {
|
||||
name: 'zhuanruinfostu',
|
||||
components: { Christianity,HigherEducation },
|
||||
data() {
|
||||
return {
|
||||
type:0,
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.getType();
|
||||
},
|
||||
methods: {
|
||||
//获取学制
|
||||
getType:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getType, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.type = resp.data;
|
||||
}else{
|
||||
_this.type=1;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,325 @@
|
||||
<template>
|
||||
<div class="student-move-wrap">
|
||||
<!-- 顶部筛选栏 -->
|
||||
<div class="top-filter-bar">
|
||||
<div class="search-wrap" style="width:100%;">
|
||||
<span>学校:</span>
|
||||
<Select v-model="filterSchool" style="width: 200px" @on-change="getselectBySchId">
|
||||
<Option value="-1">全部</Option>
|
||||
<Option v-for="item in SchoolList" :key="item.id" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
<span style="margin-left: 16px">年级:</span>
|
||||
<Select v-model="filterGrade" style="width: 140px" @on-change="getselectBySchIdAndGradeId">
|
||||
<Option value="-1">全部</Option>
|
||||
<Option v-for="item in gradeselectList" :key="item.id" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
<span style="margin-left: 16px">班级:</span>
|
||||
<Select v-model="filterClass" style="width: 140px" @on-change="handleFilterChange">
|
||||
<Option value="-1">全部</Option>
|
||||
<Option v-for="item in schclassselectlist" :key="item.id" :value="item.id">{{ item.name }}</Option>
|
||||
</Select>
|
||||
<span>
|
||||
|
||||
</span>
|
||||
<Input
|
||||
placeholder="请输入学生姓名"
|
||||
search
|
||||
@on-search="handleSearch"
|
||||
suffix="ios-search"
|
||||
class="fr"
|
||||
style="width: 280px"
|
||||
v-model="keyword"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自适应滚动表格容器 -->
|
||||
<div class="table-scroll-wrap">
|
||||
<Table
|
||||
border
|
||||
stripe
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
:height="useTableHeight()+32"
|
||||
@on-selection-change="onSelectionChange"
|
||||
></Table>
|
||||
</div>
|
||||
|
||||
<!-- 底部栏:转入按钮 + 固定分页 -->
|
||||
<div class="bottom-bar">
|
||||
<Button type="default" status="danger" @click="openMoveModal">转入</Button>
|
||||
<div class="page-area">
|
||||
<span style="margin-right: 12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,40]"
|
||||
show-sizer
|
||||
@on-change="pageChange"
|
||||
@on-page-size-change="sizeChange"
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗:转至其他组 -->
|
||||
<Modal v-model="moveModalVisible" title="转至其他组" width="540">
|
||||
<div style="padding: 15px 10px;">
|
||||
<div style="margin-bottom: 18px;display: flex;align-items: center;">
|
||||
<span style="width: 105px;">待移动用户:</span>
|
||||
<Input v-model="moveStuName" disabled style="flex:1;"></Input>
|
||||
</div>
|
||||
<div>
|
||||
<span style="width: 105px;display: inline-block;margin-bottom: 10px;color:#f56c6c;font-weight:bold;">移动至:</span>
|
||||
<my-tree :treeData="targetTreeData" @on-tree-click="treeLink"></my-tree>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="moveModalVisible = false">取消</Button>
|
||||
<Button type="primary" @click="submitMove">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myTree from "../../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: 'StudentMovePage',
|
||||
components: { myTree },
|
||||
data() {
|
||||
return {
|
||||
// 筛选条件
|
||||
filterSchool: '-1',
|
||||
filterGrade: '-1',
|
||||
filterClass: '-1',
|
||||
keyword: '',
|
||||
|
||||
// 分页
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
selectedRows: [],
|
||||
SchoolList:[],
|
||||
gradeselectList:[],
|
||||
schclassselectlist:[],
|
||||
|
||||
// 表格配置式列
|
||||
tableColumns: [],
|
||||
tableData: [],
|
||||
|
||||
// 转入弹窗
|
||||
moveModalVisible: false,
|
||||
moveStuName: '',
|
||||
selectnodeid: 0,
|
||||
// 目标学校年级树形
|
||||
targetTreeData: []
|
||||
}
|
||||
},
|
||||
mixins: [self_viewport],
|
||||
created() {
|
||||
this.getstudenttransferOutSchSelect();
|
||||
this.initTableColumn();
|
||||
this.loadTableData();
|
||||
},
|
||||
methods: {
|
||||
//获取学校下拉
|
||||
getstudenttransferOutSchSelect:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.studenttransferOutSchSelect, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.SchoolList = resp.data;
|
||||
}else{
|
||||
_this.SchoolList=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取年级
|
||||
getselectBySchId:function(){
|
||||
const _this = this;
|
||||
var item={
|
||||
schId:_this.filterSchool
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getselectBySchId, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
_this.gradeselectList = resp.data;
|
||||
}else{
|
||||
_this.gradeselectList=[];
|
||||
}
|
||||
});
|
||||
},
|
||||
//获取班级下拉
|
||||
getselectBySchIdAndGradeId:function(){
|
||||
const _this = this;
|
||||
var item={
|
||||
schId:_this.filterSchool,
|
||||
gradeId:_this.filterGrade
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getselectBySchIdAndGradeId, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.schclassselectlist=resp.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
// 初始化表格列
|
||||
initTableColumn() {
|
||||
this.tableColumns = [
|
||||
{ type: 'selection', width: 55, align: 'center' },
|
||||
{ title: '序号', type: 'index', align: 'center', width: 70 },
|
||||
{ title: '学校', key: 'schName', align: 'center' },
|
||||
{ title: '年级', key: 'gradeName', align: 'center', width: 110 },
|
||||
{ title: '班级', key: 'className', align: 'center', width: 90 },
|
||||
{ title: '姓名', key: 'name', align: 'center' },
|
||||
{ title: '身份号', key: 'idCard', align: 'center' },
|
||||
]
|
||||
},
|
||||
|
||||
// 多选勾选回调
|
||||
onSelectionChange(rows) {
|
||||
this.selectedRows = rows
|
||||
},
|
||||
|
||||
// 加载列表数据
|
||||
loadTableData() {
|
||||
const _this = this;
|
||||
var item = {
|
||||
schId:_this.filterSchool=='-1'?'':_this.filterSchool,
|
||||
gradeId:_this.filterGrade=='-1'?'':_this.filterGrade,
|
||||
classId:_this.filterClass=='-1'?'':_this.filterClass,
|
||||
keyword:_this.keyword,
|
||||
page:_this.pageNum-1,
|
||||
size:_this.pageSize
|
||||
};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getstudentsearchTransferOut, item, resp => {
|
||||
if (resp.code == 0) {
|
||||
_this.tableData = resp.data.content;
|
||||
_this.total=resp.data.total;
|
||||
} else {
|
||||
_this.tableData = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 下拉筛选切换
|
||||
handleFilterChange() {
|
||||
this.pageNum = 1
|
||||
this.loadTableData()
|
||||
},
|
||||
|
||||
// 关键词搜索
|
||||
handleSearch() {
|
||||
this.pageNum = 1
|
||||
this.loadTableData()
|
||||
},
|
||||
|
||||
// 分页切换
|
||||
pageChange(p) {
|
||||
this.pageNum = p
|
||||
this.loadTableData()
|
||||
},
|
||||
sizeChange(size) {
|
||||
this.pageSize = size
|
||||
this.pageNum = 1
|
||||
this.loadTableData()
|
||||
},
|
||||
|
||||
// 打开转入弹窗
|
||||
openMoveModal() {
|
||||
if (!this.selectedRows.length) {
|
||||
return this.$Message.warning('请先勾选需要转入的学生')
|
||||
}
|
||||
this.moveStuName = this.selectedRows.map(a=>a.name).join(',');
|
||||
this.moveModalVisible = true;
|
||||
this.getClassTree();
|
||||
},
|
||||
//获取班级树
|
||||
getClassTree:function(){
|
||||
const _this = this;
|
||||
var item={};
|
||||
_this.$api.get(APIConfig.BschClassSystem.getClassTree, item, resp => {
|
||||
if(resp.code==0)
|
||||
{
|
||||
this.targetTreeData=resp.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
// 树形选中切换
|
||||
treeLink(treeNode) {
|
||||
this.selectnodeid=treeNode.id;
|
||||
},
|
||||
// 提交迁移班级
|
||||
submitMove() {
|
||||
if (!this.selectnodeid) {
|
||||
return this.$Message.warning('请选择目标年级节点')
|
||||
}
|
||||
const teacherIdArr = this.selectedRows.map(row => row.id);
|
||||
let item={
|
||||
stuIds:teacherIdArr,
|
||||
transferClassId:this.selectnodeid
|
||||
};
|
||||
const url = APIConfig.BschClassSystem.studentsetTransferIn;
|
||||
this.$api.post(url,JSON.stringify(item), resp => {
|
||||
if (resp.code == 0) {
|
||||
this.$Message.success('学生转入分组成功!');
|
||||
this.moveModalVisible = false
|
||||
this.selectedRows = []
|
||||
this.loadTableData()
|
||||
} else if (resp.code == 4) {
|
||||
this.$Message.info(resp.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.student-move-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
/* 顶部筛选栏 */
|
||||
.top-filter-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 14px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.filter-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 表格自适应滚动容器 */
|
||||
.table-scroll-wrap {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 底部栏:分页固定底部 */
|
||||
.bottom-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 14px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.page-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,285 @@
|
||||
<template>
|
||||
<div class="student-move-wrap">
|
||||
<!-- 顶部筛选栏 -->
|
||||
<div class="top-filter-bar">
|
||||
<div class="search-wrap" style="width:100%;">
|
||||
<span>学校:</span>
|
||||
<Select v-model="filterSchool" style="width: 200px" @on-change="handleFilterChange">
|
||||
<Option value="">全部</Option>
|
||||
<Option value="上海市大宁国际小学">上海市大宁国际小学</Option>
|
||||
<Option value="上海市浦东新区崂山小学 (陆家嘴校区)">上海市浦东新区崂山小学 (陆家嘴校区)</Option>
|
||||
<Option value="上海市西延安中学">上海市西延安中学</Option>
|
||||
</Select>
|
||||
<span style="margin-left: 16px">年级:</span>
|
||||
<Select v-model="filterGrade" style="width: 140px" @on-change="handleFilterChange">
|
||||
<Option value="">全部</Option>
|
||||
<Option value="五年级">五年级</Option>
|
||||
<Option value="初三">初三</Option>
|
||||
</Select>
|
||||
<span style="margin-left: 16px">班级:</span>
|
||||
<Select v-model="filterClass" style="width: 140px" @on-change="handleFilterChange">
|
||||
<Option value="">全部</Option>
|
||||
<Option value="1班">1班</Option>
|
||||
<Option value="2班">2班</Option>
|
||||
<Option value="4班">4班</Option>
|
||||
<Option value="5班">5班</option>
|
||||
<Option value="8班">8班</Option>
|
||||
</Select>
|
||||
<span>
|
||||
|
||||
</span>
|
||||
<Input
|
||||
placeholder="请输入教师姓名"
|
||||
search
|
||||
@on-search="handleSearch"
|
||||
suffix="ios-search"
|
||||
class="fr"
|
||||
style="width: 280px"
|
||||
v-model="searchName"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自适应滚动表格容器 -->
|
||||
<div class="table-scroll-wrap">
|
||||
<Table
|
||||
border
|
||||
stripe
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
:height="useTableHeight()+32"
|
||||
@on-selection-change="onSelectionChange"
|
||||
></Table>
|
||||
</div>
|
||||
|
||||
<!-- 底部栏:转入按钮 + 固定分页 -->
|
||||
<div class="bottom-bar">
|
||||
<Button type="default" status="danger" @click="openMoveModal">转入</Button>
|
||||
<div class="page-area">
|
||||
<span style="margin-right: 12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,40]"
|
||||
show-sizer
|
||||
@on-change="pageChange"
|
||||
@on-page-size-change="sizeChange"
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗:转至其他组 -->
|
||||
<Modal v-model="moveModalVisible" title="转至其他组" width="540">
|
||||
<div style="padding: 15px 10px;">
|
||||
<div style="margin-bottom: 18px;display: flex;align-items: center;">
|
||||
<span style="width: 105px;">待移动用户:</span>
|
||||
<Input v-model="moveStuName" disabled style="flex:1;"></Input>
|
||||
</div>
|
||||
<div>
|
||||
<span style="width: 105px;display: inline-block;margin-bottom: 10px;color:#f56c6c;font-weight:bold;">移动至:</span>
|
||||
<Tree
|
||||
:data="targetTreeData"
|
||||
ref="targetTree"
|
||||
single
|
||||
:selected.sync="selectedTargetNode"
|
||||
style="border:1px solid #e5e7eb;max-height:320px;overflow-y:auto;padding:8px;"
|
||||
></Tree>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<Button @click="moveModalVisible = false">取消</Button>
|
||||
<Button type="primary" @click="submitMove">提交</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: 'StudentMovePage',
|
||||
data() {
|
||||
return {
|
||||
// 筛选条件
|
||||
filterSchool: '',
|
||||
filterGrade: '',
|
||||
filterClass: '',
|
||||
keyword: '',
|
||||
|
||||
// 分页
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
total: 225,
|
||||
selectedRows: [],
|
||||
|
||||
// 表格配置式列
|
||||
tableColumns: [],
|
||||
tableData: [
|
||||
{ id: 1, serial: 1, school: '上海市大宁国际小学', grade: '五年级', className: '1班', name: '万思娴', idCard: '' },
|
||||
{ id: 2, serial: 2, school: '上海市大宁国际小学', grade: '五年级', className: '4班', name: '姜涵越', idCard: '' },
|
||||
{ id: 3, serial: 3, school: '上海市大宁国际小学', grade: '五年级', className: '5班', name: '胡又溪', idCard: '' },
|
||||
{ id: 4, serial: 4, school: '上海市大宁国际小学', grade: '五年级', className: '8班', name: '刘语桐', idCard: '' },
|
||||
{ id: 5, serial: 5, school: '上海市浦东新区崂山小学 (陆家嘴校区)', grade: '五年级', className: '1班', name: '周辛玥', idCard: '' },
|
||||
{ id: 6, serial: 6, school: '上海市浦东新区崂山小学 (陆家嘴校区)', grade: '五年级', className: '2班', name: '胡羽洁', idCard: '' },
|
||||
{ id: 7, serial: 7, school: '上海市西延安中学', grade: '初三', className: '2班', name: '吴弈辰', idCard: '' },
|
||||
{ id: 8, serial: 8, school: '上海市西延安中学', grade: '初三', className: '4班', name: '丁昉', idCard: '' },
|
||||
],
|
||||
|
||||
// 转入弹窗
|
||||
moveModalVisible: false,
|
||||
moveStuName: '',
|
||||
selectedTargetNode: null,
|
||||
// 目标学校年级树形
|
||||
targetTreeData: [
|
||||
{
|
||||
title: '上海市进才中学北校',
|
||||
expand: true,
|
||||
children: [
|
||||
{ title: '预备' },
|
||||
{ title: '初一' },
|
||||
{ title: '初二' },
|
||||
{ title: '初三' },
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
mixins: [self_viewport],
|
||||
created() {
|
||||
this.initTableColumn()
|
||||
this.loadTableData()
|
||||
},
|
||||
methods: {
|
||||
// 初始化表格列
|
||||
initTableColumn() {
|
||||
this.tableColumns = [
|
||||
{ type: 'selection', width: 55, align: 'center' },
|
||||
{ title: '序号', key: 'serial', align: 'center', width: 70 },
|
||||
{ title: '学校', key: 'school', align: 'center' },
|
||||
{ title: '年级', key: 'grade', align: 'center', width: 110 },
|
||||
{ title: '班级', key: 'className', align: 'center', width: 90 },
|
||||
{ title: '姓名', key: 'name', align: 'center' },
|
||||
{ title: '身份号', key: 'idCard', align: 'center' },
|
||||
]
|
||||
},
|
||||
|
||||
// 多选勾选回调
|
||||
onSelectionChange(rows) {
|
||||
this.selectedRows = rows
|
||||
},
|
||||
|
||||
// 加载列表数据
|
||||
loadTableData() {
|
||||
console.log('筛选参数:', this.filterSchool, this.filterGrade, this.filterClass, this.keyword, this.pageNum, this.pageSize)
|
||||
/* 后端接口示例
|
||||
this.$axios.get('/api/student/move/list', {
|
||||
params: {
|
||||
school: this.filterSchool,
|
||||
grade: this.filterGrade,
|
||||
className: this.filterClass,
|
||||
keyword: this.keyword,
|
||||
pageNum: this.pageNum,
|
||||
pageSize: this.pageSize
|
||||
}
|
||||
}).then(res => {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
})
|
||||
*/
|
||||
},
|
||||
|
||||
// 下拉筛选切换
|
||||
handleFilterChange() {
|
||||
this.pageNum = 1
|
||||
this.loadTableData()
|
||||
},
|
||||
|
||||
// 关键词搜索
|
||||
handleSearch() {
|
||||
this.pageNum = 1
|
||||
this.loadTableData()
|
||||
},
|
||||
|
||||
// 分页切换
|
||||
pageChange(p) {
|
||||
this.pageNum = p
|
||||
this.loadTableData()
|
||||
},
|
||||
sizeChange(size) {
|
||||
this.pageSize = size
|
||||
this.pageNum = 1
|
||||
this.loadTableData()
|
||||
},
|
||||
|
||||
// 打开转入弹窗
|
||||
openMoveModal() {
|
||||
if (!this.selectedRows.length) {
|
||||
return this.$Message.warning('请先勾选需要转入的学生')
|
||||
}
|
||||
// 单选模式:取第一个选中学生
|
||||
const row = this.selectedRows[0]
|
||||
this.moveStuName = row.name
|
||||
this.selectedTargetNode = null
|
||||
this.moveModalVisible = true
|
||||
},
|
||||
|
||||
// 提交迁移班级
|
||||
submitMove() {
|
||||
if (!this.selectedTargetNode) {
|
||||
return this.$Message.warning('请选择目标年级节点')
|
||||
}
|
||||
this.$Message.success(`已将【${this.moveStuName}】迁移至 ${this.selectedTargetNode.title}`)
|
||||
this.moveModalVisible = false
|
||||
this.selectedRows = []
|
||||
this.loadTableData()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.student-move-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
/* 顶部筛选栏 */
|
||||
.top-filter-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 14px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.filter-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 表格自适应滚动容器 */
|
||||
.table-scroll-wrap {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 底部栏:分页固定底部 */
|
||||
.bottom-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 14px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.page-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user