feat: 迁移 Vue3 + Vite + view-ui-plus(对齐 NoticeFront 框架)
- 构建:Vue CLI 4 → Vite 5,入口迁至根 index.html(含 env-config + 主题通道 loader)
- 技术栈:Vue 2.6 → Vue 3.4,view-design → view-ui-plus 1.3.24,vue-router 3 → 4(hash)
- 壳层重写:App.vue / components/layout.vue 对齐 Notice 骨架(logo-badge、icon-* 通道图标、resolveMenuPage、crumb-home 基线)
- 机械转换:具名 slot → template #x、.sync → v-model:、@click.native、$set、beforeDestroy、/deep/ → :deep()
- render:h('Button')/h('Input') → 真组件 + 扁平 props/onClick
- 组件适配:vuedraggable 4 的 #item 插槽;vue-treeselect → @zanmato/vue3-treeselect;Page 分页改 v-model + pageSize 显式回写
- 清理:删除 Vue2 死代码(layout_old/bak/child、App.Net、codeModal、未引用组件)
- 修复:深链接首次加载被重定向到首个模块(router.isReady)
验证:vite build 通过;headless CDP 全 15 路由无异常;教师列表 2 行渲染、操作列按钮点击弹窗正常。
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
# 开发环境(vite dev --mode dev 加载;build 产物不读任何 .env.*)
|
||||
# 主题通道:index.html 的 loader 与 vite.config.ts 的 /static 代理已经就位;
|
||||
# 联调本地通道源时用环境变量覆盖代理目标:
|
||||
# YH_THEME_PROXY_TARGET=http://localhost:9527 npm run dev
|
||||
#
|
||||
# serviceHost 留空 → API 走同源相对 /api/*,由 vite proxy 转发到本地后端(规避 CAS 不回 CORS 头)
|
||||
VITE_BASE_HOST=http://base.yunhaixingtong.com
|
||||
VITE_SSO_HOST=http://sso.yunhaixingtong.com
|
||||
VITE_SERVICE_HOST=
|
||||
VITE_IS_MOCK=false
|
||||
@@ -1,11 +0,0 @@
|
||||
# 开发环境(Vue CLI 默认 mode=development 时自动加载本文件)
|
||||
#
|
||||
# 主题通道接入说明(《云海子应用前端接入规范》§2.2 第一步):
|
||||
# 1. public/index.html 已插入 A 类 loader,主题/皮肤由通道 /static/js/yh-theme-init.js 下发;
|
||||
# 2. 本地 dev 的 /static 请求由 vue.config.js 的 devServer.proxy 兜到主题通道;
|
||||
# 3. 默认通道地址 http://base.yunhaixingtong.com,联调本地通道源时用环境变量覆盖:
|
||||
# YH_THEME_PROXY_TARGET=http://localhost:9527 npm run dev
|
||||
# 4. 跨源直连(VITE_THEME_HOST)是 Vite 工程的机制,本项目为 Vue CLI(webpack),
|
||||
# 内联脚本里的 %VITE_THEME_HOST% 会被判为占位符并置空,统一走上面的 dev 代理。
|
||||
#
|
||||
# 说明:本文件不含敏感配置,仅作接入连法备忘。
|
||||
@@ -0,0 +1,5 @@
|
||||
# 本地纯前端调试模式:仅 vite dev --mode mock 加载
|
||||
VITE_BASE_HOST=
|
||||
VITE_SSO_HOST=
|
||||
VITE_SERVICE_HOST=http://localhost:8101
|
||||
VITE_IS_MOCK=true
|
||||
@@ -1,11 +0,0 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
"@vue/app",
|
||||
{
|
||||
polyfills: ["es6.promise", "es6.symbol", "es6.array.iterator", "es6.object.assign"],
|
||||
useBuiltIns: "entry"
|
||||
}
|
||||
]
|
||||
]
|
||||
};
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta content="telephone=no,email=no" name="format-detection" />
|
||||
<!-- 运行时配置引导:在任何应用模块执行前同步拉取 /<contextPath>/api/env-config
|
||||
(后端免登录端点,projman 配置管理在线维护),替代生产构建环境变量。
|
||||
本应用产物部署于 /{contextPath}/front/,target 取 URL 第 2 段。 -->
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var seg = location.pathname.split("/").filter(Boolean);
|
||||
if (seg.length < 2) return; // 本地开发(根路径):走 .env.dev / .env.mock
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "/" + seg[0] + "/api/env-config?target=" + encodeURIComponent(seg[1]), false);
|
||||
xhr.send(null);
|
||||
if (xhr.status === 200) {
|
||||
var conf = JSON.parse(xhr.responseText);
|
||||
if (conf && typeof conf === "object") window.__APP_CONFIG__ = conf;
|
||||
}
|
||||
} catch (e) {
|
||||
/* 拉取失败保持未设置,走同域推导兜底 */
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<!-- 主题通道引导(A 类免插件接入,YschTheme《管理端主题远程化与公共静态通道方案》§11):
|
||||
唯一接入点。FOUC 门、manifest 预取、主题 <link> 追加与排序(晚于 viewuiplus.css)全由
|
||||
通道 yh-theme-init.js 承担;主题升级走 /static 通道,本应用无需重新构建。
|
||||
origin 零写死,优先级四档:__APP_CONFIG__.staticHost > __APP_CONFIG__.baseHost
|
||||
> %VITE_THEME_HOST%(仅 dev) > 同源相对 "/static/…"(生产常态,本地 dev 走 vite 代理)。 -->
|
||||
<script>
|
||||
(function () {
|
||||
var c = window.__APP_CONFIG__ || {};
|
||||
var themeHost = "%VITE_THEME_HOST%";
|
||||
if (themeHost.charAt(0) === "%") themeHost = "";
|
||||
var host = String(c.staticHost || c.baseHost || themeHost).replace(/\/+$/, "");
|
||||
document.write('<script src="' + host + '/static/js/yh-theme-init.js"><\/script>');
|
||||
})();
|
||||
</script>
|
||||
<title><%- title %></title>
|
||||
<link rel="stylesheet" href="./libs/ztree/zTreeStyle.css" />
|
||||
<script src="./libs/jquery.min.js"></script>
|
||||
<script src="./libs/ztree/jquery.ztree.all.min.js"></script>
|
||||
<%- injectScript %>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Generated
+4575
-28920
File diff suppressed because it is too large
Load Diff
+32
-27
@@ -1,29 +1,34 @@
|
||||
{
|
||||
"name": "bschstandard",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/polyfill": "^7.12.1",
|
||||
"@riophae/vue-treeselect": "^0.4.0",
|
||||
"core-js": "^3.6.5",
|
||||
"node-sass": "latest",
|
||||
"sortablejs": "^1.15.7",
|
||||
"view-design": "^4.3.2",
|
||||
"vue": "^2.6.11",
|
||||
"vue-router": "^3.2.0",
|
||||
"vuedraggable": "^2.24.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-router": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"sass": "^1.56.1",
|
||||
"node-sass": "^6.0.1",
|
||||
"sass-loader": "^10.2.0",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
}
|
||||
"name": "bschclass",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --mode dev",
|
||||
"dev:mock": "vite --mode mock",
|
||||
"build": "vite build --mode base",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@zanmato/vue3-treeselect": "^0.4.4",
|
||||
"alova": "3.4.0",
|
||||
"axios": "0.24.0",
|
||||
"highlight.js": "11.9.0",
|
||||
"mitt": "3.0.1",
|
||||
"pinia": "2.1.4",
|
||||
"sortablejs": "1.15.7",
|
||||
"view-ui-plus": "1.3.24",
|
||||
"vue": "3.4.19",
|
||||
"vue-router": "4.3.0",
|
||||
"vuedraggable": "4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "20.4.4",
|
||||
"@vitejs/plugin-vue": "5.0.4",
|
||||
"sass": "1.64.1",
|
||||
"typescript": "5.2.2",
|
||||
"vite": "5.1.4",
|
||||
"vite-plugin-html": "3.2.2",
|
||||
"vue-tsc": "1.8.27"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||
<meta content="telephone=no,email=no" name="format-detection" />
|
||||
<meta http-equiv="Access-Control-Allow-Origin" content="*" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<script src="./config/index.js"></script>
|
||||
<link rel="stylesheet" href="./libs/base.layout.css" />
|
||||
<link rel="stylesheet" href="./libs/default-theme.css" />
|
||||
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_4962449_bwzjcx59wz4.css" />
|
||||
<!-- 主题通道引导(A 类免插件接入,见 YschTheme《管理端主题远程化与公共静态通道方案》§11):
|
||||
唯一接入点。不装 npm 依赖、不改构建配置;FOUC 门、manifest 预取、主题 <link> 追加与
|
||||
排序(晚于 viewuiplus.css)全由通道 yh-theme-init.js 承担,主题升级走 /static 通道,
|
||||
本应用无需重新构建。
|
||||
origin 零写死,优先级四档:__APP_CONFIG__.staticHost(专用通道覆盖)
|
||||
> __APP_CONFIG__.baseHost(env-config 在线维护,换域名改配置即生效)
|
||||
> %VITE_THEME_HOST%(仅 dev 注入的跨源直连,需通道已开 CORS)
|
||||
> 同源相对 "/static/…"(生产常态:本应用部署在 base 域 /<app>/front/,与通道同源;
|
||||
本地 dev 由 vue.config.js 的 /static 代理兜到通道)。
|
||||
document.write 是有意为之:保证 parser-blocking,让档位类与 FOUC 门先于首帧;
|
||||
build 不读 .env,占位符留字面量 → 判首字符 % 置空 → 产物零环境值烧入。 -->
|
||||
<script>
|
||||
(function () {
|
||||
var c = window.__APP_CONFIG__ || {};
|
||||
var themeHost = "%VITE_THEME_HOST%";
|
||||
if (themeHost.charAt(0) === "%") themeHost = "";
|
||||
var host = String(c.staticHost || c.baseHost || themeHost).replace(/\/+$/, "");
|
||||
document.write('<script src="' + host + '/static/js/yh-theme-init.js"><\/script>');
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="./libs/vue.js"></script>
|
||||
<script src="./libs/jquery.min.js"></script>
|
||||
<script src="./libs/axios.js"></script>
|
||||
<script src="./libs/clipboard.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
-211
@@ -1,211 +0,0 @@
|
||||
<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>
|
||||
+145
-232
@@ -1,246 +1,159 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted, provide, nextTick } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { Message } from "view-ui-plus";
|
||||
import layout from "@/components/layout.vue";
|
||||
import conf from "@/assets/config/host.config";
|
||||
import api from "@/api";
|
||||
import { resolveMenuPage } from "@/utils/menuRoute";
|
||||
|
||||
const router = useRouter();
|
||||
const isLogin = ref(false);
|
||||
const isNoAuthority = ref(false);
|
||||
const isRouterAlive = ref(true);
|
||||
|
||||
const layoutData = reactive<any>({
|
||||
appName: "学校管理",
|
||||
baseHost: conf.baseHost,
|
||||
ssoHost: conf.ssoHost,
|
||||
appList: [],
|
||||
userInfo: null,
|
||||
modList: [],
|
||||
isAlone: false,
|
||||
});
|
||||
|
||||
const reload = () => {
|
||||
isRouterAlive.value = false;
|
||||
nextTick(() => (isRouterAlive.value = true));
|
||||
};
|
||||
provide("reload", reload);
|
||||
|
||||
const getUserInfo = () =>
|
||||
new Promise<any>((resolve, reject) => {
|
||||
api.get(APIConfig.Base.GetUserInfo, null, (resp: any) => resolve(resp.data), reject);
|
||||
});
|
||||
|
||||
const getUserMod = () =>
|
||||
new Promise<any>((resolve, reject) => {
|
||||
api.get(APIConfig.Base.GetUserMod, null, (resp: any) => resolve(resp.data), reject);
|
||||
});
|
||||
|
||||
/** 平台模块 → 侧边栏菜单项:icon 取路由 meta(icon-* 通道图标名) */
|
||||
const layoutInit = (info: any, mod: any[]) => {
|
||||
const routes: any[] = (router.options.routes as any[]) || [];
|
||||
const arr = (mod || [])
|
||||
.map((element: any) => {
|
||||
const hit = routes.find(
|
||||
x => x.meta && x.meta.modId !== undefined && x.meta.modId == element.customId
|
||||
);
|
||||
return {
|
||||
id: element.id,
|
||||
name: element.name,
|
||||
modId: element.customId,
|
||||
page: element.path,
|
||||
children: element.children || [],
|
||||
icon: (hit && hit.meta && hit.meta.icon) || "",
|
||||
};
|
||||
})
|
||||
.sort((a: any, b: any) => a.modId - b.modId);
|
||||
|
||||
layoutData.modList = arr;
|
||||
const hasChildren = arr.some((m: any) => m.children && m.children.length > 0);
|
||||
layoutData.isAlone = arr.length <= 1 && !hasChildren;
|
||||
|
||||
const { id, name, profilePicture } = info || {};
|
||||
layoutData.userInfo = { id, name: name || "管理员", avatar: profilePicture || "" };
|
||||
layoutData.appList = [];
|
||||
|
||||
if (arr.length === 0) {
|
||||
layoutData.isAlone = true;
|
||||
isNoAuthority.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const info = await getUserInfo();
|
||||
localStorage.setItem(
|
||||
"currentRole",
|
||||
encodeURI(
|
||||
JSON.stringify({
|
||||
childId: 0,
|
||||
roleId: info.roleIds[0],
|
||||
schId: info.school ? info.school.id : 0,
|
||||
userId: info.id,
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
let mod = await getUserMod();
|
||||
if (info.type == 1) mod = mod.filter((a: any) => a.customId < 4);
|
||||
|
||||
layoutInit(info, mod);
|
||||
isLogin.value = true;
|
||||
|
||||
// 等首次导航解析完成再判断,否则深链接(如 /#/teacherManage)会被误判成 "/"
|
||||
// 而重定向到第一个模块(Vue Router 初始导航是异步的)
|
||||
await router.isReady();
|
||||
|
||||
// 登录后跳转第一个可用模块
|
||||
if (router.currentRoute.value.path === "/") {
|
||||
const firstModule = (mod || [])[0];
|
||||
const firstRaw = firstModule?.children?.length ? firstModule.children[0] : firstModule;
|
||||
const first = resolveMenuPage(
|
||||
firstRaw?.page,
|
||||
firstRaw?.customId ?? firstRaw?.id,
|
||||
firstRaw?.name
|
||||
);
|
||||
if (!first.external && first.path && first.path !== "/") {
|
||||
router.replace(first.path);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Message.error("载入用户信息失败!");
|
||||
layoutData.userInfo = { name: "管理员", avatar: "" };
|
||||
layoutData.modList = [];
|
||||
layoutData.isAlone = true;
|
||||
isNoAuthority.value = true;
|
||||
isLogin.value = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<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">
|
||||
<layout v-if="isLogin" :layoutData="layoutData" />
|
||||
<div v-if="isLogin" class="base-wrap-main" :class="{ 'alone-page': layoutData.isAlone }">
|
||||
<div class="main-wrapper">
|
||||
<div v-if="isNoAuthority" class="no-authority-wrap">
|
||||
<h3>暂无权限</h3>
|
||||
<h6>如需查看,请联络管理员为您分配权限</h6>
|
||||
</div>
|
||||
<router-view v-else-if="isRouterAlive" :key="$route.fullPath" />
|
||||
</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);
|
||||
localStorage.setItem("currentRole", encodeURI(JSON.stringify({ childId:0, roleId:info.roleIds[0], schId:info.school?info.school.id:0, userId:info.id })));
|
||||
var mod = await this.getUserMod();
|
||||
if(info.type==1){
|
||||
mod=mod.filter(a=>a.customId<4)
|
||||
}
|
||||
this.layoutInit(info, mod, [], 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 => {
|
||||
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);
|
||||
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.customId
|
||||
);
|
||||
let icon = iconIndex > -1 ? "iconfont " + routes[iconIndex].meta.icon : ""; //icon不传则为默认
|
||||
arr.push({
|
||||
id: element.id,
|
||||
name: element.name,
|
||||
modId: element.customId,
|
||||
page: element.path,
|
||||
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;
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 开始过渡阶段,动画出去阶段 */
|
||||
.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%;
|
||||
}
|
||||
/* 页面级滚动容器:main-wrapper 只有 min-height 时内容超一屏会被 body 的 overflow:hidden 裁掉 */
|
||||
.base-wrap-main .main-wrapper {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
/* 表格操作列(render 出的 Tooltip 包裹层)横排且随单元格居中 */
|
||||
.ivu-table-cell > .ivu-tooltip {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin: 0 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
+4
-3
@@ -1,13 +1,14 @@
|
||||
// 配置API接口地址
|
||||
// var root = '/api/v1'
|
||||
// var root = '/api/debugapi'
|
||||
var root = "/api";
|
||||
// 置空:APIConfig 已带 /api 前缀(生产为绝对地址,dev 为同源相对),避免 baseURL 二次拼接
|
||||
var root = "";
|
||||
// var root = ''
|
||||
// 引用axios
|
||||
var axios = require("axios");
|
||||
import axios from "axios";
|
||||
|
||||
// import Notice from 'iview/src/components/notice';
|
||||
import { Message } from "view-design";
|
||||
import { Message } from "view-ui-plus";
|
||||
|
||||
// 自定义判断元素类型JS
|
||||
function toType(obj) {
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
// 配置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);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 宿主配置(对齐 NoticeFront @/assets/config/host.config)。
|
||||
* 优先级:__APP_CONFIG__(线上运行时下发)> VITE_*(仅本地 dev)> 同域推导兜底。
|
||||
*/
|
||||
const env = import.meta.env;
|
||||
|
||||
const seg = window.location.pathname.split("/").filter(Boolean);
|
||||
const origin = window.location.origin;
|
||||
// 部署在 /{contextPath}/front/ → 上下文段即首段;本地 dev 根路径段数不足 → 留空走同源相对
|
||||
const ctx = seg.length >= 2 ? `/${seg[0]}` : "";
|
||||
|
||||
export interface BaseConf {
|
||||
baseHost: string;
|
||||
ssoHost: string;
|
||||
serviceHost: string;
|
||||
serviceUrl: string;
|
||||
fileHost: string;
|
||||
flowHost: string;
|
||||
isLayoutOld: boolean;
|
||||
isMock: boolean;
|
||||
isDebug: boolean;
|
||||
}
|
||||
|
||||
const conf: BaseConf = {
|
||||
baseHost: origin,
|
||||
ssoHost: "",
|
||||
serviceHost: ctx ? origin + ctx : "",
|
||||
serviceUrl: ctx ? origin + ctx : "",
|
||||
fileHost: ctx ? origin + ctx : "",
|
||||
flowHost: "",
|
||||
isLayoutOld: false,
|
||||
isMock: false,
|
||||
isDebug: env.DEV,
|
||||
};
|
||||
|
||||
const applyConf = (target: any, source: any) => {
|
||||
if (!source || typeof source !== "object") return;
|
||||
Object.keys(source).forEach(key => {
|
||||
if (source[key] !== undefined && source[key] !== null && source[key] !== "") {
|
||||
target[key] = source[key];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 本地开发/演示(build 产物中 VITE_* 恒 undefined → 自动跳过)
|
||||
applyConf(conf, {
|
||||
baseHost: env.VITE_BASE_HOST,
|
||||
ssoHost: env.VITE_SSO_HOST,
|
||||
serviceHost: env.VITE_IS_MOCK === "true" ? "" : env.VITE_SERVICE_HOST,
|
||||
serviceUrl: env.VITE_IS_MOCK === "true" ? "" : env.VITE_SERVICE_HOST,
|
||||
fileHost: env.VITE_IS_MOCK === "true" ? "" : env.VITE_SERVICE_HOST,
|
||||
isMock: env.VITE_IS_MOCK === "true",
|
||||
});
|
||||
|
||||
// 线上运行时配置(最高优先)
|
||||
try {
|
||||
const runtime: any = (window as any).__APP_CONFIG__;
|
||||
if (runtime && typeof runtime === "object") {
|
||||
applyConf(conf, {
|
||||
baseHost: runtime.baseHost,
|
||||
ssoHost: runtime.ssoHost,
|
||||
serviceHost: runtime.serviceHost,
|
||||
serviceUrl: runtime.serviceHost,
|
||||
fileHost: runtime.serviceHost,
|
||||
flowHost: runtime.flowHost,
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
/* 无运行时配置时沿用兜底 */
|
||||
}
|
||||
|
||||
export default conf;
|
||||
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
||||
<path fill="#4aaff0" d="M512,585 C415,455 330,398 215,395 C185,395 160,415 160,450 L160,770 C160,815 190,838 240,845 C340,856 430,872 512,888 C594,872 684,856 784,845 C834,838 864,815 864,770 L864,450 C864,415 839,395 809,395 C694,398 609,455 512,585 Z"/>
|
||||
<path fill="#4aaff0" d="M218,312 C335,292 462,352 514,462 C452,404 334,354 218,378 Z"/>
|
||||
<circle fill="#4aaff0" cx="218" cy="345" r="33"/>
|
||||
<path fill="#80d976" d="M508,462 C455,310 525,145 700,105 C758,250 668,425 508,462 Z"/>
|
||||
<path fill="none" stroke="#4aaff0" stroke-width="44" stroke-linecap="round" d="M210,935 Q285.5,881 361,935 T512,935 T663,935 T814,935"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 701 B |
@@ -1,473 +0,0 @@
|
||||
$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;
|
||||
}
|
||||
@@ -1,505 +0,0 @@
|
||||
<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>
|
||||
@@ -1,80 +0,0 @@
|
||||
<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>
|
||||
@@ -1,54 +0,0 @@
|
||||
<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>
|
||||
@@ -1,24 +0,0 @@
|
||||
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;
|
||||
};
|
||||
@@ -1,240 +0,0 @@
|
||||
<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,291 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onBeforeMount, onBeforeUnmount, onMounted, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { Message } from "view-ui-plus";
|
||||
import { resolveMenuPage } from "@/utils/menuRoute";
|
||||
import defaultLogo from "@/assets/image/yunhai-logo.svg";
|
||||
|
||||
const props = defineProps<{ layoutData: any }>();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const currPath = ref("");
|
||||
const navPath = ref<any[]>([]);
|
||||
|
||||
const baseHost = computed(() => props.layoutData?.baseHost || "");
|
||||
const ssoHost = computed(() => props.layoutData?.ssoHost || "");
|
||||
const appName = computed(() => props.layoutData?.appName || "学校管理");
|
||||
const userInfo = computed(() => props.layoutData?.userInfo || { name: "管理员", avatar: "" });
|
||||
const isAlone = computed(() => props.layoutData?.isAlone ?? false);
|
||||
const modList = computed<any[]>(() => props.layoutData?.modList || []);
|
||||
|
||||
const pathNavStyle = computed(() => (isAlone.value ? { left: "0", width: "100%" } : null));
|
||||
|
||||
/* 顶栏 Logo:平台键 yh-logo-url(yh-theme-init 外观补齐段写入)优先,本仓资产兜底 */
|
||||
const logoUrl = ref<string>(defaultLogo);
|
||||
const readLogoUrl = () => {
|
||||
let v: string | null = null;
|
||||
try {
|
||||
v = localStorage.getItem("yh-logo-url");
|
||||
} catch {
|
||||
v = null;
|
||||
}
|
||||
logoUrl.value = v || defaultLogo;
|
||||
};
|
||||
const onLogoError = () => {
|
||||
if (logoUrl.value !== defaultLogo) logoUrl.value = defaultLogo;
|
||||
};
|
||||
onMounted(() => {
|
||||
readLogoUrl();
|
||||
document.addEventListener("yh-appearance-updated", readLogoUrl);
|
||||
});
|
||||
onBeforeUnmount(() => document.removeEventListener("yh-appearance-updated", readLogoUrl));
|
||||
|
||||
/* 头像:URL 为空或加载失败时回落首字 */
|
||||
const avatarFailed = ref(false);
|
||||
watch(
|
||||
() => userInfo.value?.avatar,
|
||||
() => (avatarFailed.value = false)
|
||||
);
|
||||
const avatarText = computed(() => String(userInfo.value?.name || "?").trim().slice(0, 1));
|
||||
|
||||
const flaten = (tree: any[], pid = 0): any[] => {
|
||||
const arr: any[] = [];
|
||||
(tree || []).forEach((element: any) => {
|
||||
const { id, name, modId } = element;
|
||||
const resolved = resolveMenuPage(element.page, element.modId ?? element.id, element.name);
|
||||
arr.push({ id, name, modId, page: resolved.path, external: resolved.external, pid });
|
||||
if (element.children && element.children.length) {
|
||||
arr.push(...flaten(element.children, id));
|
||||
}
|
||||
});
|
||||
return arr;
|
||||
};
|
||||
|
||||
const menuArr = computed(() => flaten(modList.value));
|
||||
|
||||
const routeChange = (to: any) => {
|
||||
const meta: any = to.meta || {};
|
||||
const { modId, title, parentId } = meta;
|
||||
const navArr: any[] = [];
|
||||
|
||||
const find: any =
|
||||
menuArr.value.find((x: any) => x.page && x.page === to.path) ||
|
||||
menuArr.value.find((x: any) => x.modId === modId);
|
||||
if (find) {
|
||||
currPath.value = find.page || "";
|
||||
if (find.pid) {
|
||||
const pfind = menuArr.value.find((x: any) => x.id === find.pid);
|
||||
if (pfind) navArr.push({ name: pfind.name });
|
||||
}
|
||||
navArr.push({ name: find.name || title, page: find.page });
|
||||
navPath.value = navArr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (parentId) {
|
||||
const parent = menuArr.value.find((x: any) => x.modId === parentId);
|
||||
if (parent) {
|
||||
currPath.value = parent.page || "";
|
||||
if (parent.pid) {
|
||||
const gp = menuArr.value.find((x: any) => x.id === parent.pid);
|
||||
if (gp) navArr.push({ name: gp.name });
|
||||
}
|
||||
navArr.push({ name: parent.name, page: parent.page });
|
||||
navArr.push({ name: title });
|
||||
navPath.value = navArr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const r = router.getRoutes().find((rt: any) => (rt.meta as any)?.modId === modId);
|
||||
if (r) {
|
||||
currPath.value = r.path;
|
||||
navPath.value = [{ name: (r.meta as any).title, page: r.path }];
|
||||
return;
|
||||
}
|
||||
|
||||
currPath.value = "";
|
||||
navPath.value = [];
|
||||
};
|
||||
|
||||
onBeforeMount(() => routeChange(route));
|
||||
watch(
|
||||
() => route.fullPath,
|
||||
() => routeChange(route)
|
||||
);
|
||||
|
||||
const resolveItemPage = (item: any) =>
|
||||
resolveMenuPage(item?.page, item?.modId ?? item?.id, item?.name);
|
||||
const pageOf = (item: any): string => resolveItemPage(item).path;
|
||||
|
||||
const linkMenu = (item: any) => {
|
||||
const { path: page, external } = resolveItemPage(item);
|
||||
if (!page) {
|
||||
Message.warning(`菜单「${item?.name || "未命名"}」未配置有效页面路径,请检查基础平台模块设置`);
|
||||
return;
|
||||
}
|
||||
if (external) {
|
||||
window.location.href = page;
|
||||
return;
|
||||
}
|
||||
if (page === route.path) {
|
||||
router.go(0);
|
||||
} else {
|
||||
router.push(page);
|
||||
}
|
||||
};
|
||||
|
||||
const linkHomePage = () => {
|
||||
if (baseHost.value) {
|
||||
window.location.href = baseHost.value + "/userhome/front/index.html";
|
||||
} else {
|
||||
window.location.href = "/";
|
||||
}
|
||||
};
|
||||
|
||||
const linkUserInfo = () => {
|
||||
window.location.href = baseHost.value + "/userhome/front/index.html#/settings?pane=profile";
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
let url = window.location.href;
|
||||
url = "/logout?service=" + url;
|
||||
window.location.href = ssoHost.value + url;
|
||||
};
|
||||
|
||||
const childChange = (index: number) => {
|
||||
const arr = modList.value || [];
|
||||
if (arr[index]) arr[index].childState = !arr[index].childState;
|
||||
};
|
||||
|
||||
/* 菜单图标:路由 meta 的 icon-* 通道图标名;未配置统一兜底 icon-list */
|
||||
const getMenuIcon = (item?: any): string => item?.icon || "icon-list";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="layout-wrap">
|
||||
<header class="header-container fix">
|
||||
<span class="logo-badge fl"><img :src="logoUrl" alt="云海" @error="onLogoError" /></span>
|
||||
<div class="delimiter fl align-middle"></div>
|
||||
<h4 class="fl align-middle">{{ appName }}</h4>
|
||||
<div class="school-bg"></div>
|
||||
<div class="header-aside fr">
|
||||
<span class="avatar-wrap fl align-middle" @click="linkUserInfo">
|
||||
<img
|
||||
v-if="userInfo.avatar && !avatarFailed"
|
||||
:src="userInfo.avatar"
|
||||
alt=""
|
||||
@error="avatarFailed = true"
|
||||
/>
|
||||
<span v-else class="avatar-text">{{ avatarText }}</span>
|
||||
</span>
|
||||
<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="退出登陆">
|
||||
<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 modList" :key="'menu_li_' + index">
|
||||
<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>
|
||||
<i :class="['iconfont', getMenuIcon(item)]"></i>
|
||||
{{ item.name }}
|
||||
</a>
|
||||
</li>
|
||||
<transition name="fade_child_ul">
|
||||
<div class="child-item-wrap" v-show="item.childState">
|
||||
<li
|
||||
:class="pageOf(citem) == currPath ? 'active child-item' : 'child-item'"
|
||||
v-for="citem in item.children"
|
||||
:key="citem.id"
|
||||
>
|
||||
<a href="javascript:;" @click="linkMenu(citem)">
|
||||
{{ citem.name }}
|
||||
</a>
|
||||
</li>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
<li v-else :class="pageOf(item) == currPath ? 'active' : ''">
|
||||
<a href="javascript:;" @click="linkMenu(item)">
|
||||
<i :class="['iconfont', getMenuIcon(item)]"></i>
|
||||
{{ item.name }}
|
||||
</a>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
<div class="clear-box"></div>
|
||||
</div>
|
||||
|
||||
<div class="path-nav" :style="pathNavStyle">
|
||||
<Breadcrumb separator=">">
|
||||
<a href="javascript:;" @click="linkHomePage">
|
||||
<BreadcrumbItem>
|
||||
<span class="crumb-home">
|
||||
<i class="iconfont icon-shouye"></i>
|
||||
首页
|
||||
</span>
|
||||
</BreadcrumbItem>
|
||||
</a>
|
||||
<BreadcrumbItem v-if="!isAlone" to="/">{{ appName }}</BreadcrumbItem>
|
||||
<template v-for="(item, index) in navPath" :key="index">
|
||||
<BreadcrumbItem v-if="index != navPath.length - 1" :to="item.page">
|
||||
{{ item.name }}
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbItem v-else>{{ item.name }}</BreadcrumbItem>
|
||||
</template>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 仅覆盖必要动态样式;骨架与皮肤全部来自中央静态通道 base.layout.css */
|
||||
.left-menu a .iconfont {
|
||||
margin-right: 8px;
|
||||
}
|
||||
.header-container .logo-badge {
|
||||
margin: 0 10px 0 0;
|
||||
}
|
||||
.header-aside .avatar-wrap {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
margin-right: 14px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
background: rgba(255, 255, 255, 0.22);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.header-aside .avatar-wrap img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
.header-aside .avatar-text {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
}
|
||||
/* 面包屑「首页」:行内基线流 -0.125em 光学居中(接入规范 §4) */
|
||||
.crumb-home .iconfont {
|
||||
position: static;
|
||||
top: 0;
|
||||
margin-right: 4px;
|
||||
vertical-align: -0.125em;
|
||||
}
|
||||
</style>
|
||||
@@ -1,64 +0,0 @@
|
||||
<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>
|
||||
@@ -1,23 +0,0 @@
|
||||
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;
|
||||
};
|
||||
@@ -1,95 +0,0 @@
|
||||
<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>
|
||||
@@ -3,8 +3,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
require("@public/libs/ztree/zTreeStyle.css");
|
||||
import "@public/libs/ztree/jquery.ztree.all.min.js";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
treeData: {
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
<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>
|
||||
@@ -1,169 +0,0 @@
|
||||
<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>
|
||||
@@ -1,100 +0,0 @@
|
||||
<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>
|
||||
@@ -48,16 +48,15 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<template #footer><div>
|
||||
<i-Button type="primary" @click="submit">提交</i-Button>
|
||||
<i-Button @click="modal = false" style="margin-left: 8px">取消</i-Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
require("@public/libs/ztree/zTreeStyle.css");
|
||||
import "@public/libs/ztree/jquery.ztree.all.min.js";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
treeData: {
|
||||
@@ -79,10 +78,6 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
model: {
|
||||
prop: "userids",
|
||||
event: "change",
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ztreeDomId: null,
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
let conf = {
|
||||
baseHost: "http://base.yunhaixingtong.com",
|
||||
ssoHost: "http://sso.yunhaixingtong.com",
|
||||
serviceUrl: "http://base.yunhaixingtong.com/userclass",
|
||||
fileHost: "http://base.yunhaixingtong.com/userclass",
|
||||
isLayoutOld: false
|
||||
// serviceUrl: "http://basedebug.bestsch.com/BschHome/",
|
||||
};
|
||||
import conf from "@/assets/config/host.config";
|
||||
|
||||
if (typeof window.conf !== "undefined") conf = window.conf;
|
||||
// 兼容旧代码:全局 window.conf 与默认导出
|
||||
if (typeof window !== "undefined") {
|
||||
window.conf = conf;
|
||||
}
|
||||
|
||||
export default conf;
|
||||
|
||||
@@ -1,251 +0,0 @@
|
||||
<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>
|
||||
@@ -1,305 +0,0 @@
|
||||
<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>
|
||||
@@ -1,306 +0,0 @@
|
||||
<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
@@ -1,62 +0,0 @@
|
||||
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");
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
import { createApp } from "vue";
|
||||
import { createPinia } from "pinia";
|
||||
|
||||
import App from "./App.vue";
|
||||
import router from "@/router";
|
||||
|
||||
import ViewUIPlus from "view-ui-plus";
|
||||
import "view-ui-plus/dist/styles/viewuiplus.css";
|
||||
|
||||
// 布局/主题/图标(base.layout.css + icons.css)由中央静态通道下发:
|
||||
// index.html 的 yh-theme-init.js 在 DOMContentLoaded 后按 manifest 版本追加 <link>,
|
||||
// 天然排在本文件组件库样式之后。
|
||||
import "@/assets/styles/main.scss";
|
||||
|
||||
import api from "@/api";
|
||||
import utils from "@/utils";
|
||||
import conf from "@/assets/config/host.config";
|
||||
import bus from "@/utils/bus";
|
||||
import registerDirectives from "@/utils/directive";
|
||||
import APIConfig from "@/config/apiConf";
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
app.use(createPinia());
|
||||
app.use(router);
|
||||
app.use(ViewUIPlus);
|
||||
|
||||
// 兼容存量代码:全局 APIConfig / conf,以及 Vue2 时代的四个原型方法
|
||||
(window as any).APIConfig = APIConfig;
|
||||
(window as any).conf = conf;
|
||||
|
||||
app.config.globalProperties.$api = api;
|
||||
app.config.globalProperties.$utils = utils;
|
||||
app.config.globalProperties.$conf = conf;
|
||||
app.config.globalProperties.$bus = bus;
|
||||
|
||||
registerDirectives(app);
|
||||
|
||||
app.mount("#app");
|
||||
@@ -1,8 +0,0 @@
|
||||
import codeModal from "../components/codeModal/index.js";
|
||||
export default {
|
||||
methods: {
|
||||
showCode({ name, url, type = "vue" }) {
|
||||
codeModal({ name, url, type });
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,141 +0,0 @@
|
||||
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: "/studySystemChoice",
|
||||
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,9 @@
|
||||
import { createRouter, createWebHashHistory } from "vue-router";
|
||||
import routes from "./routes";
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -0,0 +1,138 @@
|
||||
import type { RouteRecordRaw } 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");
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: "/",
|
||||
name: "root",
|
||||
component: { render: () => null },
|
||||
},
|
||||
{
|
||||
path: "/studySystemChoice",
|
||||
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" },
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
declare module "*.vue" {
|
||||
import type { DefineComponent } from "vue";
|
||||
const component: DefineComponent<{}, {}, any>;
|
||||
export default component;
|
||||
}
|
||||
|
||||
declare const APIConfig: any;
|
||||
declare const $: any;
|
||||
declare const jQuery: any;
|
||||
|
||||
interface Window {
|
||||
conf: any;
|
||||
APIConfig: any;
|
||||
__APP_CONFIG__: any;
|
||||
__YH_THEME_STATIC_BASE__?: string;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import mitt from "mitt";
|
||||
|
||||
/**
|
||||
* 事件总线:保留 Vue2 时代的 $on / $off / $emit 调用形态,
|
||||
* 业务代码(layout 的 setNavPath / setMenuPath)无需改动。
|
||||
*/
|
||||
const emitter = mitt();
|
||||
|
||||
const bus = {
|
||||
$on: emitter.on,
|
||||
$off: emitter.off,
|
||||
$emit: emitter.emit,
|
||||
on: emitter.on,
|
||||
off: emitter.off,
|
||||
emit: emitter.emit,
|
||||
};
|
||||
|
||||
export default bus;
|
||||
@@ -0,0 +1,12 @@
|
||||
import hljs from "highlight.js";
|
||||
|
||||
/** 代码高亮指令(Vue3:mounted 替代 Vue2 的 bind/inserted) */
|
||||
export default function registerDirectives(app: any) {
|
||||
app.directive("highlight", {
|
||||
mounted(el: HTMLElement) {
|
||||
el.querySelectorAll("pre code").forEach(block => {
|
||||
hljs.highlightElement(block as HTMLElement);
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
+3
-3
@@ -43,15 +43,15 @@ export default {
|
||||
const loop = function (nodes, parentNode) {
|
||||
for (let node of nodes) {
|
||||
// 清空所有节点选中状态
|
||||
vueThis.$set(node, 'selected', false)
|
||||
node.selected = false
|
||||
|
||||
if (node.id === targetId) {
|
||||
// 目标节点设为选中
|
||||
vueThis.$set(node, 'selected', true)
|
||||
node.selected = true
|
||||
let p = parentNode
|
||||
// 逐层向上展开父节点
|
||||
while (p) {
|
||||
vueThis.$set(p, 'expand', true)
|
||||
p.expand = true
|
||||
p = p._parent
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
import routes from "@/router/routes";
|
||||
|
||||
/**
|
||||
* 平台模块配置 → 前端内部路由的统一解析器(对齐 NoticeFront @/utils/menuRoute)。
|
||||
* 平台配置的 path 格式不可控(旧前缀 / index.html#/hash / 完整 URL / 配错),
|
||||
* 侧边栏跳转与高亮、登录后默认跳转都必须先经过这里,禁止手拼路由。
|
||||
*/
|
||||
const ROUTE_PATHS: string[] = routes
|
||||
.map((r: any) => (typeof r.redirect === "string" ? r.redirect : r.path))
|
||||
.filter((p: any): p is string => !!p && !String(p).includes(":"));
|
||||
|
||||
const ROUTE_BY_MODID = new Map<number, string>();
|
||||
for (const r of routes as any[]) {
|
||||
const modId = r.meta?.modId as number | undefined;
|
||||
if (!modId || !r.path || String(r.path).includes(":") || r.redirect) continue;
|
||||
if (!ROUTE_BY_MODID.has(modId)) ROUTE_BY_MODID.set(modId, r.path);
|
||||
}
|
||||
|
||||
const ROUTE_BY_TITLE = new Map<string, string>();
|
||||
for (const r of routes as any[]) {
|
||||
if (r.redirect || !r.path || String(r.path).includes(":")) continue;
|
||||
const title = r.meta?.title as string | undefined;
|
||||
if (title && !ROUTE_BY_TITLE.has(title)) ROUTE_BY_TITLE.set(title, r.path);
|
||||
}
|
||||
|
||||
/** 平台历史模块名 → 路由(旧菜单叫法与现页面标题不一致时的对照) */
|
||||
const NAME_ALIASES: Record<string, string> = {
|
||||
学制设置: "/studySystemChoice",
|
||||
时段管理: "/itemSet",
|
||||
学校管理: "/schoolSetting",
|
||||
课程管理: "/subjectManForZy",
|
||||
学科设置: "/subjectSetzhi",
|
||||
班级列表: "/classManage",
|
||||
选修班: "/electiveClassManage",
|
||||
教师列表: "/teacherManage",
|
||||
学生列表: "/studentManage",
|
||||
日志查询: "/dailySearch",
|
||||
};
|
||||
|
||||
/** 本应用历史上下文前缀(/bschclass、/userclass、/BschClassSystem)→ 去掉后比对 */
|
||||
const LEGACY_PREFIXES = ["/bschclass", "/userclass", "/bschclasssystem"];
|
||||
|
||||
const EXTERNAL_RE = /^(https?:)?\/\//i;
|
||||
|
||||
function extractCandidate(raw: string): string {
|
||||
let p = raw.trim();
|
||||
try {
|
||||
p = decodeURIComponent(p);
|
||||
} catch {
|
||||
/* 非法编码保持原样 */
|
||||
}
|
||||
const hashIdx = p.indexOf("#");
|
||||
if (hashIdx >= 0) {
|
||||
p = p.slice(hashIdx + 1);
|
||||
} else if (EXTERNAL_RE.test(p)) {
|
||||
try {
|
||||
p = new URL(p, "http://placeholder.local").pathname;
|
||||
} catch {
|
||||
/* 保持原样 */
|
||||
}
|
||||
}
|
||||
const qIdx = p.indexOf("?");
|
||||
if (qIdx >= 0) p = p.slice(0, qIdx);
|
||||
p = p.replace(/index\.html?$/i, "");
|
||||
p = p.replace(/\/+$/, "");
|
||||
if (p && !p.startsWith("/")) p = "/" + p;
|
||||
return p;
|
||||
}
|
||||
|
||||
function matchRoute(candidate: string): string | null {
|
||||
if (!candidate) return null;
|
||||
const lower = candidate.toLowerCase();
|
||||
const exact = ROUTE_PATHS.find((p: string) => p.toLowerCase() === lower);
|
||||
if (exact) return exact;
|
||||
for (const prefix of LEGACY_PREFIXES) {
|
||||
if (lower.startsWith(prefix + "/")) {
|
||||
const stripped = lower.slice(prefix.length);
|
||||
const hit = ROUTE_PATHS.find((p: string) => p.toLowerCase() === stripped);
|
||||
if (hit) return hit;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function matchByName(name?: string | null): string | null {
|
||||
const n = String(name ?? "").trim();
|
||||
if (!n) return null;
|
||||
const byTitle = ROUTE_BY_TITLE.get(n);
|
||||
if (byTitle) return byTitle;
|
||||
const alias = NAME_ALIASES[n];
|
||||
if (alias) return alias;
|
||||
const hits = [...ROUTE_BY_TITLE.entries()].filter(
|
||||
([title]) => title.length >= 2 && (n.includes(title) || title.includes(n))
|
||||
);
|
||||
return hits.length === 1 ? hits[0][1] : null;
|
||||
}
|
||||
|
||||
function isAppEntryCandidate(candidate: string): boolean {
|
||||
if (!candidate || candidate === "/") return true;
|
||||
return LEGACY_PREFIXES.some(p => candidate === p);
|
||||
}
|
||||
|
||||
export interface ResolvedMenuPage {
|
||||
path: string;
|
||||
external: boolean;
|
||||
}
|
||||
|
||||
export const EMPTY_MENU_PAGE: ResolvedMenuPage = { path: "", external: false };
|
||||
|
||||
export function resolveMenuPage(
|
||||
page?: string | null,
|
||||
modId?: number | null,
|
||||
name?: string | null
|
||||
): ResolvedMenuPage {
|
||||
const raw = String(page ?? "").trim();
|
||||
const byName = (): string | null => matchByName(name);
|
||||
const byModId = (): string | null => (modId != null ? ROUTE_BY_MODID.get(modId) ?? null : null);
|
||||
|
||||
if (raw) {
|
||||
const candidate = extractCandidate(raw);
|
||||
const byPath = matchRoute(candidate);
|
||||
if (byPath) return { path: byPath, external: false };
|
||||
|
||||
if (EXTERNAL_RE.test(raw) && !raw.includes("#")) {
|
||||
if (!isAppEntryCandidate(candidate)) {
|
||||
return { path: raw, external: true };
|
||||
}
|
||||
}
|
||||
|
||||
const fallback = byName() ?? byModId();
|
||||
if (fallback) return { path: fallback, external: false };
|
||||
|
||||
console.warn(
|
||||
"[menuRoute] 模块路径/名称/modId 均无法匹配前端路由,请检查基础平台模块配置:",
|
||||
raw,
|
||||
"modId =", modId,
|
||||
"name =", name
|
||||
);
|
||||
return EMPTY_MENU_PAGE;
|
||||
}
|
||||
|
||||
const fallback = byName() ?? byModId();
|
||||
if (fallback) return { path: fallback, external: false };
|
||||
console.warn("[menuRoute] 模块未配置路径且名称/modId 无法识别:", name, "modId =", modId);
|
||||
return EMPTY_MENU_PAGE;
|
||||
}
|
||||
@@ -28,7 +28,7 @@
|
||||
<div class="pagination-wrap">
|
||||
<span class="total-text">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
v-model="pageNum"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:page-size-opts="[10, 20, 50, 100]"
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
添加班级
|
||||
<Icon type="ios-arrow-down"></Icon>
|
||||
</Button>
|
||||
<DropdownMenu slot="list">
|
||||
<template #list><DropdownMenu>
|
||||
<DropdownItem name="openAddSingleClass">添加单个班级</DropdownItem>
|
||||
<DropdownItem name="openMultiNumModal">添加多个班级</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</DropdownMenu></template>
|
||||
</Dropdown>
|
||||
<Button type="success" style="margin-left:10px" @click="openImportModal">班级信息导入</Button>
|
||||
</div>
|
||||
@@ -42,10 +42,10 @@
|
||||
<Input v-model.number="addClassCount" type="number" min="1" />
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="multiClassModal = false">取消</Button>
|
||||
<Button type="primary" @click="submitBatchAdd">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗2:班级信息导入 -->
|
||||
@@ -61,9 +61,9 @@
|
||||
<Button type="primary" @click="confirmImport">确定</Button>
|
||||
</div> -->
|
||||
<div class="main-contents">
|
||||
<Form ref="UpParmas.datapre" :model="UpParmas.datapre" :label-width="100" inline>
|
||||
<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>
|
||||
<Input type="text" style="width:90%;" v-model="UpParmas.fileName" class="import-input" placeholder="未选中任何文件.." readonly></Input>
|
||||
<Upload class="fr btn"
|
||||
:action="UpParmas.actionUrl"
|
||||
:data="UpParmas.datapre"
|
||||
@@ -73,7 +73,7 @@
|
||||
:before-upload="handleUpload"
|
||||
:on-success="importFile"
|
||||
>
|
||||
<i-button icon="md-add"></i-button>
|
||||
<Button icon="md-add"></Button>
|
||||
</Upload>
|
||||
</FormItem>
|
||||
<FormItem v-if="UpParmas.fileName" style="margin-bottom:10px">
|
||||
@@ -84,8 +84,8 @@
|
||||
|
||||
<Alert show-icon>
|
||||
操作说明:
|
||||
<Icon type="ios-bulb-outline" slot="icon" size="20"></Icon>
|
||||
<template slot="desc" style="font-size: 12px;">
|
||||
<template #icon><Icon type="ios-bulb-outline" size="20"></Icon></template>
|
||||
<template #desc style="font-size: 12px;">
|
||||
请先上传EXCEL文件,若成功则显示导入成功数据,否则显示错误的数据及错误原因;<br>
|
||||
EXCEL文件的格式():工作表(WorkSheet)的名称应设为缺省的[Sheet1];<br>
|
||||
<a @click="MoBanExceldaochu" style="font-size:12px;">点击链接下载[班级导入模板.xls]</a>
|
||||
@@ -98,9 +98,9 @@
|
||||
<Icon type="ios-loading" size=30 class="demo-spin-icon-load"></Icon>
|
||||
<div>上传中...</div>
|
||||
</Spin>
|
||||
<div slot="footer">
|
||||
<template #footer><div>
|
||||
<i-Button @click="UpfileModalcloseclick" style="margin-left: 8px">关闭</i-Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗3:选择教师 -->
|
||||
@@ -119,10 +119,10 @@
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="selectTeacherModal = false">取消</Button>
|
||||
<Button type="primary" @click="confirmSelectTeacher">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗5:选择校区 -->
|
||||
@@ -135,15 +135,16 @@
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="selectCampusModal = false">取消</Button>
|
||||
<Button type="primary" @click="confirmSelectCampus">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button, Input } from "view-ui-plus";
|
||||
import myTree from "../../components/my_tree";
|
||||
export default {
|
||||
components: { myTree},
|
||||
@@ -336,16 +337,12 @@ export default {
|
||||
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)
|
||||
return h(Input, {modelValue: params.row.cname,
|
||||
'onUpdate:modelValue': (val) => {
|
||||
params.row.classAlias = val
|
||||
this.cellChange(params.index, 'classAlias', val)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
style: { width: '150px' }})
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -543,14 +540,10 @@ export default {
|
||||
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) }
|
||||
})
|
||||
h(Button, {icon: 'ios-eye-outline', type: 'text', size: 'large',
|
||||
onClick: () => this.viewDetail(params.row)}),
|
||||
h(Button, {icon: 'ios-trash-outline', type: 'text', color: 'red', size: 'large',disabled:params.row.disableDel,
|
||||
onClick: () => this.deleteRow(params.index, params.row)})
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<!-- <div class="pagination-bottom">
|
||||
<span class="total-text">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
v-model="pageNum"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:page-size-opts="[10,20,50]"
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
<!-- 设置教师弹窗 -->
|
||||
<Modal v-model="modalVisible" title="选择教师" width="400">
|
||||
<Form ref="form" :model="formData" :rules="formRules" label-width="90">
|
||||
<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>
|
||||
@@ -75,10 +75,10 @@
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="modalVisible = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitSelectTeacher">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
style="width:200px"
|
||||
@keyup.enter="searchList"
|
||||
>
|
||||
<Icon slot="suffix" type="ios-search" @click="searchList" style="cursor:pointer;"></Icon>
|
||||
<template #suffix><Icon type="ios-search" @click="searchList" style="cursor:pointer;"></Icon></template>
|
||||
</Input>
|
||||
</div>
|
||||
</div>
|
||||
@@ -49,7 +49,7 @@
|
||||
<div class="pagination-bottom">
|
||||
<span class="total-text">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
v-model="pageNum"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:page-size-opts="[10,20,50]"
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
<!-- 新增/编辑班级弹窗 -->
|
||||
<Modal v-model="modalVisible" :title="modalTitle" width="520">
|
||||
<Form ref="form" :model="formData" :rules="formRules" label-width="110">
|
||||
<Form ref="form" :model="formData" :rules="formRules" :label-width="110">
|
||||
<FormItem label="班级代码">
|
||||
<Input v-model="formData.classCode" placeholder="请输入班级代码"></Input>
|
||||
</FormItem>
|
||||
@@ -95,17 +95,17 @@
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="modalVisible = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitForm">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
<!-- 班级信息导入 -->
|
||||
<Modal v-model="importModal" title="班级信息导入" width="560">
|
||||
<div class="main-contents">
|
||||
<Form ref="UpParmas.datapre" :model="UpParmas.datapre" :label-width="100" inline>
|
||||
<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>
|
||||
<Input type="text" style="width:90%;" v-model="UpParmas.fileName" class="import-input" placeholder="未选中任何文件.." readonly></Input>
|
||||
<Upload class="fr btn"
|
||||
:action="UpParmas.actionUrl"
|
||||
:data="UpParmas.datapre"
|
||||
@@ -115,7 +115,7 @@
|
||||
:before-upload="handleUpload"
|
||||
:on-success="importFile"
|
||||
>
|
||||
<i-button icon="md-add"></i-button>
|
||||
<Button icon="md-add"></Button>
|
||||
</Upload>
|
||||
</FormItem>
|
||||
<FormItem v-if="UpParmas.fileName" style="margin-bottom:10px">
|
||||
@@ -126,8 +126,8 @@
|
||||
|
||||
<Alert show-icon>
|
||||
操作说明:
|
||||
<Icon type="ios-bulb-outline" slot="icon" size="20"></Icon>
|
||||
<template slot="desc" style="font-size: 12px;">
|
||||
<template #icon><Icon type="ios-bulb-outline" size="20"></Icon></template>
|
||||
<template #desc style="font-size: 12px;">
|
||||
请先上传EXCEL文件,若成功则显示导入成功数据,否则显示错误的数据及错误原因;<br>
|
||||
EXCEL文件的格式():工作表(WorkSheet)的名称应设为缺省的[Sheet1];<br>
|
||||
<a @click="MoBanExceldaochu" style="font-size:12px;">点击链接下载[班级导入模板.xls]</a>
|
||||
@@ -140,15 +140,16 @@
|
||||
<Icon type="ios-loading" size=30 class="demo-spin-icon-load"></Icon>
|
||||
<div>上传中...</div>
|
||||
</Spin>
|
||||
<div slot="footer">
|
||||
<template #footer><div>
|
||||
<i-Button @click="UpfileModalcloseclick" style="margin-left: 8px">关闭</i-Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myTree from "../../components/my_tree";
|
||||
import { Button } from "view-ui-plus";
|
||||
import myTree from "../../components/my_tree";
|
||||
export default {
|
||||
name: 'HigherEducation',
|
||||
components: { myTree},
|
||||
@@ -193,18 +194,12 @@
|
||||
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) }
|
||||
})
|
||||
h(Button, {type: 'text', icon: 'ios-eye', size: 'large',
|
||||
onClick: () => this.viewDetail(params.row)}),
|
||||
h(Button, {type: 'text', icon: 'ios-create', size: 'large',
|
||||
onClick: () => this.editRow(params.row, params.index)}),
|
||||
h(Button, {type: 'text', icon: 'ios-trash', size: 'large',
|
||||
onClick: () => this.delRow(params.index)})
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<div class="page-wrap">
|
||||
<span style="margin-right:12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
v-model="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,50,100]"
|
||||
@@ -159,7 +159,7 @@
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
.table-scroll-wrap :deep(.ivu-table) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,14 +77,14 @@
|
||||
</div>
|
||||
<div class="page-pagination">
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
:page-size.sync="pageSize"
|
||||
v-model="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,50]"
|
||||
show-sizer
|
||||
show-total
|
||||
@on-change="loadTableData"
|
||||
@on-page-size-change="loadTableData"
|
||||
@on-page-size-change="v => { pageSize = v; loadTableData(); }"
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
@@ -92,39 +92,39 @@
|
||||
|
||||
<!-- 弹窗1:新增校本分组 -->
|
||||
<Modal v-model="addGroupModal" title="添加组" width="420">
|
||||
<Form ref="groupForm" :model="groupForm" :rules="groupRules" label-width="80">
|
||||
<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">
|
||||
<template #footer><div 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>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗2:编辑校本分组(对标截图红框弹窗) -->
|
||||
<Modal v-model="editGroupModal" title="编辑组" width="420">
|
||||
<Form ref="editGroupForm" :model="editGroupForm" :rules="editGroupRules" label-width="80">
|
||||
<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">
|
||||
<template #footer><div 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>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗3:新增选修班 -->
|
||||
<Modal v-model="addClassModal" title="添加选修班" width="560">
|
||||
<Form ref="addClassForm" :model="addClassForm" :rules="addClassRules" label-width="100">
|
||||
<Form ref="addClassForm" :model="addClassForm" :rules="addClassRules" :label-width="100">
|
||||
<FormItem label="*班级名称" prop="className">
|
||||
<Input v-model="addClassForm.className" placeholder="请输入班级名称"></Input>
|
||||
</FormItem>
|
||||
@@ -183,15 +183,15 @@
|
||||
<Input v-model.number="addClassForm.studentNum" placeholder="请输入计划招生人数"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="addClassModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitAddClass">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗4:编辑选修班(完全匹配截图布局) -->
|
||||
<Modal v-model="editClassModal" title="编辑选修班" width="560">
|
||||
<Form ref="editClassForm" :model="editClassForm" :rules="addClassRules" label-width="100">
|
||||
<Form ref="editClassForm" :model="editClassForm" :rules="addClassRules" :label-width="100">
|
||||
<FormItem label="*班级名称" prop="className">
|
||||
<Input v-model="editClassForm.className"></Input>
|
||||
</FormItem>
|
||||
@@ -229,10 +229,10 @@
|
||||
</div>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="editClassModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitEditClass">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗5:班级信息导入 -->
|
||||
@@ -243,10 +243,10 @@
|
||||
<Upload action="" :before-upload="()=>false">
|
||||
<Button icon="ios-cloud-upload-outline">选择要上传的文件</Button>
|
||||
</Upload>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="importClassModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="confirmImportClass">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗6:学生导入 -->
|
||||
@@ -257,34 +257,35 @@
|
||||
<Upload action="" :before-upload="()=>false">
|
||||
<Button icon="ios-cloud-upload-outline">选择要上传的文件</Button>
|
||||
</Upload>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="importStudentModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="confirmImportStudent">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 批量删除确认弹窗 -->
|
||||
<Modal v-model="delConfirmModal" title="提示" width="360">
|
||||
<Alert type="warning" show-icon>确认批量删除选中班级?删除后不可恢复</Alert>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="delConfirmModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="error" @click="confirmBatchDel">确定删除</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 删除分组二次确认弹窗 -->
|
||||
<Modal v-model="delGroupConfirmModal" title="删除分组提示" width="380">
|
||||
<Alert type="error" show-icon>确定删除该分组?分组下所有班级将会一并删除,不可恢复!</Alert>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="delGroupConfirmModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="error" @click="doDelGroup">确认删除</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
import { Button } from "view-ui-plus";
|
||||
export default {
|
||||
name: "CurriculumElectiveClass",
|
||||
data() {
|
||||
return {
|
||||
@@ -323,20 +324,14 @@
|
||||
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, {type: "text", icon: "ios-create", size: "large",
|
||||
onClick: () => this.openEditClass(params.row)}),
|
||||
// 学生管理
|
||||
h("Button", {
|
||||
props: { type: "text", icon: "ios-people", size: "large" },
|
||||
on: { click: () => this.openStudentManage(params.row) }
|
||||
}),
|
||||
h(Button, {type: "text", icon: "ios-people", size: "large",
|
||||
onClick: () => this.openStudentManage(params.row)}),
|
||||
// 同步刷新
|
||||
h("Button", {
|
||||
props: { type: "text", icon: "ios-refresh", size: "large" },
|
||||
on: { click: () => this.singleSync(params.row) }
|
||||
})
|
||||
h(Button, {type: "text", icon: "ios-refresh", size: "large",
|
||||
onClick: () => this.singleSync(params.row)})
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -755,24 +750,24 @@
|
||||
|
||||
<style>
|
||||
/* 全局穿透修改iView表格,完全匹配截图:无外框、无竖线、仅行底横线 */
|
||||
/deep/ .ivu-table {
|
||||
:deep(.ivu-table) {
|
||||
border: none !important;
|
||||
}
|
||||
/deep/ .ivu-table-header th {
|
||||
:deep(.ivu-table-header th) {
|
||||
border: none;
|
||||
border-bottom: 1px solid #eee;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
}
|
||||
/deep/ .ivu-table td {
|
||||
:deep(.ivu-table td) {
|
||||
border-left: none !important;
|
||||
border-right: none !important;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
/deep/ .ivu-table-row {
|
||||
:deep(.ivu-table-row) {
|
||||
border: none;
|
||||
}
|
||||
/deep/ .ivu-table-stripe .ivu-table-row:nth-child(even) {
|
||||
:deep(.ivu-table-stripe .ivu-table-row:nth-child(even)) {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
</style>
|
||||
@@ -32,14 +32,14 @@
|
||||
<Button type="error" @click="batchDelConfirm">删除</Button>
|
||||
<div class="pagination-box">
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
:page-size.sync="pageSize"
|
||||
v-model="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="totalCount"
|
||||
:page-size-opts="[10,20,50]"
|
||||
show-sizer
|
||||
show-total
|
||||
@on-change="loadStudentData"
|
||||
@on-page-size-change="loadStudentData"
|
||||
@on-page-size-change="v => { pageSize = v; loadStudentData(); }"
|
||||
></Page>
|
||||
</div>
|
||||
</div>
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
<!-- 弹窗1:调班弹窗 -->
|
||||
<Modal v-model="transferModal" title="调班" width="680">
|
||||
<Form label-width="100">
|
||||
<Form :label-width="100">
|
||||
<FormItem label="当前班级">
|
||||
<Input v-model="currentClassName" disabled></Input>
|
||||
</FormItem>
|
||||
@@ -75,10 +75,10 @@
|
||||
</div>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="transferModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="confirmTransferStudent">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗2:学生信息导入 -->
|
||||
@@ -89,19 +89,19 @@
|
||||
<Upload action="" :before-upload="()=>false">
|
||||
<Button icon="ios-cloud-upload-outline">选择要上传的文件</Button>
|
||||
</Upload>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="importModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="confirmImport">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 批量删除二次确认弹窗 -->
|
||||
<Modal v-model="delConfirmModal" title="提示" width="360">
|
||||
<Alert type="warning" show-icon>确认删除选中学生?删除后不可恢复</Alert>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="delConfirmModal=false" style="margin-right:10px">取消</Button>
|
||||
<Button type="error" @click="doBatchDelete">确定删除</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
@@ -322,24 +322,24 @@
|
||||
|
||||
<style>
|
||||
/* 全局穿透 表格样式 与截图一致:无外框无竖线,仅行底横线 */
|
||||
/deep/ .ivu-table {
|
||||
:deep(.ivu-table) {
|
||||
border: none !important;
|
||||
}
|
||||
/deep/ .ivu-table-header th {
|
||||
:deep(.ivu-table-header th) {
|
||||
border: none;
|
||||
border-bottom: 1px solid #eee;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
}
|
||||
/deep/ .ivu-table td {
|
||||
:deep(.ivu-table td) {
|
||||
border-left: none !important;
|
||||
border-right: none !important;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
/deep/ .ivu-table-row {
|
||||
:deep(.ivu-table-row) {
|
||||
border: none;
|
||||
}
|
||||
/deep/ .ivu-table-stripe .ivu-table-row:nth-child(even) {
|
||||
:deep(.ivu-table-stripe .ivu-table-row:nth-child(even)) {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
</style>
|
||||
+19
-25
@@ -24,7 +24,7 @@
|
||||
<FormItem label="新学年">
|
||||
<Input disabled :value="addForm.year + '学年'" />
|
||||
</FormItem>
|
||||
<Row gutter="16">
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="开始日期" prop="yearStartDate">
|
||||
<DatePicker
|
||||
@@ -56,7 +56,7 @@
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
<div class="form-block-title">第一学期设置</div>
|
||||
<Row gutter="16">
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="开始日期" prop="firstTermStartDate">
|
||||
<DatePicker
|
||||
@@ -81,7 +81,7 @@
|
||||
</Col>
|
||||
</Row>
|
||||
<div class="form-block-title">第二学期设置</div>
|
||||
<Row gutter="16">
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="开始日期" prop="secondTermStartDate">
|
||||
<DatePicker
|
||||
@@ -104,10 +104,10 @@
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
<div slot="footer" class="modal-footer">
|
||||
<template #footer><div class="modal-footer">
|
||||
<Button @click="addModalVisible = false">取消</Button>
|
||||
<Button type="primary" @click="submitAdd">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
<!-- 编辑弹窗 -->
|
||||
<Modal v-model="editModalVisible" title="修改学年学期" width="720" class="modalform">
|
||||
@@ -122,7 +122,7 @@
|
||||
<FormItem label="新学年">
|
||||
<Input disabled :value="editForm.year + '学年'" />
|
||||
</FormItem>
|
||||
<Row gutter="16">
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="开始日期" prop="yearStartDate">
|
||||
<DatePicker
|
||||
@@ -151,7 +151,7 @@
|
||||
></DatePicker>
|
||||
</FormItem>
|
||||
<div class="form-block-title">第一学期设置</div>
|
||||
<Row gutter="16">
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="开始日期" prop="firstTermStartDate">
|
||||
<DatePicker
|
||||
@@ -172,7 +172,7 @@
|
||||
</Col>
|
||||
</Row>
|
||||
<div class="form-block-title">第二学期设置</div>
|
||||
<Row gutter="16">
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="开始日期" prop="secondTermStartDate">
|
||||
<DatePicker
|
||||
@@ -193,15 +193,16 @@
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
<div slot="footer" class="modal-footer">
|
||||
<template #footer><div class="modal-footer">
|
||||
<Button @click="editModalVisible = false">取消</Button>
|
||||
<Button type="primary" @click="submitEdit">保存</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
import { Button } from "view-ui-plus";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: "AcademicYearTerm",
|
||||
data() {
|
||||
@@ -268,19 +269,12 @@ export default {
|
||||
width: 90,
|
||||
align: "center",
|
||||
render: (h, params) => {
|
||||
return h(
|
||||
"Button",
|
||||
{
|
||||
props: {
|
||||
icon: "ios-create",
|
||||
shape: "circle"
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
return h(Button,
|
||||
{icon: "ios-create",
|
||||
shape: "circle",
|
||||
onClick: () => {
|
||||
this.openEditModal(params.row);
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -550,7 +544,7 @@ export default {
|
||||
padding: 10px;
|
||||
/* margin: 10px 0 15px; */
|
||||
}
|
||||
.term-table /deep/ .ivu-table-row td {
|
||||
.term-table :deep(.ivu-table-row td) {
|
||||
padding: 6px 0;
|
||||
}
|
||||
.form-block-title {
|
||||
@@ -563,7 +557,7 @@ export default {
|
||||
.modal-footer {
|
||||
text-align: right;
|
||||
}
|
||||
.modalform /deep/ .ivu-modal-body{
|
||||
.modalform :deep(.ivu-modal-body) {
|
||||
padding:10px;
|
||||
}
|
||||
</style>
|
||||
+36
-45
@@ -11,24 +11,22 @@
|
||||
<div class="btn-container">
|
||||
<draggable
|
||||
v-model="campuslist"
|
||||
animation="150"
|
||||
item-key="name"
|
||||
:animation="150"
|
||||
ghost-class="drag-ghost"
|
||||
class="drag-box"
|
||||
:options="{ group: 'people' }"
|
||||
group="people"
|
||||
@start="drag = true"
|
||||
@end="drag = false"
|
||||
:move="getdata1"
|
||||
@update="datadragEnd1"
|
||||
@change="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>
|
||||
<template #item="{ element, index }">
|
||||
<div class="tag-wrap" @dblclick="openEditModal('campus', index)">
|
||||
<div class="tag-btn">{{ element.name }}</div>
|
||||
<span class="close-btn" @click.stop="delCampus(index)">×</span>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
<Button icon="ios-add" size="large" class="add-btn" @click="openAddModal('campus')">添加校区</Button>
|
||||
</div>
|
||||
@@ -43,24 +41,22 @@
|
||||
<div class="btn-container">
|
||||
<draggable
|
||||
v-model="divisionlist"
|
||||
animation="150"
|
||||
item-key="name"
|
||||
:animation="150"
|
||||
ghost-class="drag-ghost"
|
||||
class="drag-box"
|
||||
:options="{ group: 'people' }"
|
||||
group="people"
|
||||
@start="drag = true"
|
||||
@end="drag = false"
|
||||
:move="getdata2"
|
||||
@update="datadragEnd2"
|
||||
@change="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>
|
||||
<template #item="{ element, index }">
|
||||
<div class="tag-wrap" @dblclick="openEditModal('dept', index)">
|
||||
<div class="tag-btn">{{ element.name }}</div>
|
||||
<span class="close-btn" @click.stop="delDept(index)">×</span>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
<Button icon="ios-add" size="large" class="add-btn" @click="openAddModal('dept')">添加系部</Button>
|
||||
</div>
|
||||
@@ -80,7 +76,7 @@
|
||||
placeholder="输入代码或名称搜索"
|
||||
@keyup.enter="searchMajor"
|
||||
>
|
||||
<Icon slot="suffix" type="ios-search" @click="searchMajor" style="cursor:pointer;"></Icon>
|
||||
<template #suffix><Icon type="ios-search" @click="searchMajor" style="cursor:pointer;"></Icon></template>
|
||||
</i-Input>
|
||||
</div>
|
||||
</div>
|
||||
@@ -98,7 +94,7 @@
|
||||
<!-- <div class="pagination-fixed-bottom">
|
||||
<span class="total-desc">共 {{ majorTotal }} 条</span>
|
||||
<Page
|
||||
:current.sync="majorPageNum"
|
||||
v-model="majorPageNum"
|
||||
:total="majorTotal"
|
||||
:page-size="majorPageSize"
|
||||
:page-size-opts="[10,20,50]"
|
||||
@@ -111,7 +107,7 @@
|
||||
|
||||
<!-- 校区/系部 新增编辑弹窗 -->
|
||||
<Modal v-model="modalVisible" :title="modalTitle" width="420">
|
||||
<Form ref="formRef" :model="formData" :rules="formRule" label-width="90">
|
||||
<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>
|
||||
@@ -119,15 +115,15 @@
|
||||
<Input v-model="formData.name" placeholder="请输入系部名称" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="modalVisible = false" style="margin-right: 10px">取消</Button>
|
||||
<Button type="primary" @click="submitModal">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 专业新增编辑弹窗 -->
|
||||
<Modal v-model="majorModalVisible" :title="majorModalTitle" width="460">
|
||||
<Form ref="majorFormRef" :model="majorForm" :rules="majorFormRule" label-width="90">
|
||||
<Form ref="majorFormRef" :model="majorForm" :rules="majorFormRule" :label-width="90">
|
||||
<FormItem label="专业代码">
|
||||
<Input v-model="majorForm.code" placeholder="请输入专业代码" />
|
||||
</FormItem>
|
||||
@@ -138,15 +134,16 @@
|
||||
<Input v-model="majorForm.schsystemLeng" type="number" placeholder="请输入学制" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="majorModalVisible = false" style="margin-right: 10px">取消</Button>
|
||||
<Button type="primary" @click="submitMajorModal">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button, Icon } from "view-ui-plus";
|
||||
import draggable from 'vuedraggable'
|
||||
import Sortable from 'sortablejs'
|
||||
export default {
|
||||
@@ -190,19 +187,13 @@ export default {
|
||||
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) }
|
||||
}),
|
||||
h(Button, {type: 'text', icon: 'ios-create', size: 'small',
|
||||
onClick: () => this.openMajorEdit(params.index)}),
|
||||
h(Button, {type: 'text', icon: 'ios-trash', size: 'small',
|
||||
onClick: () => this.delMajor(params.index)}),
|
||||
// 拖拽把手class固定为 drag-handle
|
||||
h('Icon', {
|
||||
props: { type: 'ios-move', size: 18, title: '拖动排序' },
|
||||
class: 'drag-handle drag-icon'
|
||||
})
|
||||
h(Icon, {type: 'ios-move', size: 18, title: '拖动排序',
|
||||
class: 'drag-handle drag-icon'})
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -246,7 +237,7 @@ export default {
|
||||
}
|
||||
}, 120)
|
||||
},
|
||||
beforeDestroy() {
|
||||
beforeUnmount() {
|
||||
if (this.tableDrag) this.tableDrag.destroy()
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
<div class="page-right">
|
||||
<span style="margin-right:12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
v-model="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,40,50]"
|
||||
@@ -61,7 +61,7 @@
|
||||
|
||||
<!-- 弹窗1:添加学生 -->
|
||||
<Modal v-model="addModalVisible" title="添加学生" width="560">
|
||||
<Form ref="addForm" :model="addForm" :rules="formRules" label-width="90">
|
||||
<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>
|
||||
@@ -88,15 +88,15 @@
|
||||
<Input v-model="addForm.pwd" type="password" placeholder="请输入密码"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="addModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitAddStudent">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗2:编辑学生 -->
|
||||
<Modal v-model="editModalVisible" title="编辑学生" width="560">
|
||||
<Form ref="editForm" :model="editForm" :rules="formRules" label-width="90">
|
||||
<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>
|
||||
@@ -120,10 +120,10 @@
|
||||
<Input v-model="editForm.account"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="editModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitEditStudent">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗3:学生信息导入 -->
|
||||
@@ -141,9 +141,9 @@
|
||||
<Button type="primary" @click="confirmImport">确定</Button>
|
||||
</div> -->
|
||||
<div class="main-contents">
|
||||
<Form ref="UpParmas.datapre" :model="UpParmas.datapre" :label-width="100" inline>
|
||||
<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>
|
||||
<Input type="text" style="width:90%;" v-model="UpParmas.fileName" class="import-input" placeholder="未选中任何文件.." readonly></Input>
|
||||
<Upload class="fr btn"
|
||||
:action="UpParmas.actionUrl"
|
||||
:data="UpParmas.datapre"
|
||||
@@ -153,7 +153,7 @@
|
||||
:before-upload="handleUpload"
|
||||
:on-success="importFile"
|
||||
>
|
||||
<i-button icon="md-add"></i-button>
|
||||
<Button icon="md-add"></Button>
|
||||
</Upload>
|
||||
</FormItem>
|
||||
<FormItem v-if="UpParmas.fileName" style="margin-bottom:10px">
|
||||
@@ -164,8 +164,8 @@
|
||||
|
||||
<Alert show-icon>
|
||||
操作说明:
|
||||
<Icon type="ios-bulb-outline" slot="icon" size="20"></Icon>
|
||||
<template slot="desc" style="font-size: 12px;">
|
||||
<template #icon><Icon type="ios-bulb-outline" size="20"></Icon></template>
|
||||
<template #desc style="font-size: 12px;">
|
||||
请先上传EXCEL文件,若成功则显示导入成功数据,否则显示错误的数据及错误原因;<br>
|
||||
EXCEL文件的格式():工作表(WorkSheet)的名称应设为缺省的[Sheet1];<br>
|
||||
<a @click="MoBanExceldaochu" style="font-size:12px;">点击链接下载[学生信息导入模板.xls]</a>
|
||||
@@ -178,17 +178,17 @@
|
||||
<Icon type="ios-loading" size=30 class="demo-spin-icon-load"></Icon>
|
||||
<div>上传中...</div>
|
||||
</Spin>
|
||||
<div slot="footer">
|
||||
<template #footer><div>
|
||||
<i-Button @click="UpfileModalcloseclick" style="margin-left: 8px">关闭</i-Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗4:学号导入 -->
|
||||
<Modal v-model="stuIdImportModalVisible" title="学生学号导入" width="520">
|
||||
<div class="main-contents">
|
||||
<Form ref="UpParmas2.datapre" :model="UpParmas2.datapre" :label-width="100" inline>
|
||||
<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>
|
||||
<Input type="text" style="width:90%;" v-model="UpParmas2.fileName" class="import-input" placeholder="未选中任何文件.." readonly></Input>
|
||||
<Upload class="fr btn"
|
||||
:action="UpParmas2.actionUrl"
|
||||
:data="UpParmas2.datapre"
|
||||
@@ -198,7 +198,7 @@
|
||||
:before-upload="handleUpload2"
|
||||
:on-success="importFile2"
|
||||
>
|
||||
<i-button icon="md-add"></i-button>
|
||||
<Button icon="md-add"></Button>
|
||||
</Upload>
|
||||
</FormItem>
|
||||
<FormItem v-if="UpParmas2.fileName" style="margin-bottom:10px">
|
||||
@@ -209,8 +209,8 @@
|
||||
|
||||
<Alert show-icon>
|
||||
操作说明:
|
||||
<Icon type="ios-bulb-outline" slot="icon" size="20"></Icon>
|
||||
<template slot="desc" style="font-size: 12px;">
|
||||
<template #icon><Icon type="ios-bulb-outline" size="20"></Icon></template>
|
||||
<template #desc style="font-size: 12px;">
|
||||
请先上传EXCEL文件,若成功则显示导入成功数据,否则显示错误的数据及错误原因;<br>
|
||||
EXCEL文件的格式():工作表(WorkSheet)的名称应设为缺省的[Sheet1];<br>
|
||||
<a @click="MoBanExceldaochu2" style="font-size:12px;">点击链接下载[学生学号信息导入模板.xls]</a>
|
||||
@@ -223,9 +223,9 @@
|
||||
<Icon type="ios-loading" size=30 class="demo-spin-icon-load"></Icon>
|
||||
<div>上传中...</div>
|
||||
</Spin>
|
||||
<div slot="footer">
|
||||
<template #footer><div>
|
||||
<i-Button @click="UpfileModalcloseclick2" style="margin-left: 8px">关闭</i-Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗5:学生调班 -->
|
||||
@@ -249,10 +249,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="moveClassModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitMoveClass">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗6:学生异动 -->
|
||||
@@ -276,25 +276,26 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="changeStatusModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitChangeStatus">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗7:转出学生弹窗 -->
|
||||
<Modal v-model="transferStudentModal" title="转出学生" width="420">
|
||||
<p>确认将选中学生做转出操作?</p>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="transferStudentModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="confirmTransferStudent">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myTree from "../../components/my_tree";
|
||||
import { Button } from "view-ui-plus";
|
||||
import myTree from "../../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: 'StudentManage',
|
||||
@@ -513,10 +514,8 @@
|
||||
align: 'center',
|
||||
width: 80,
|
||||
render: (h, params) => {
|
||||
return h('Button', {
|
||||
props: { type: 'text', icon: 'md-create', size: 'large' },
|
||||
on: { click: () => this.openEditStudent(params.row) }
|
||||
})
|
||||
return h(Button, {type: 'text', icon: 'md-create', size: 'large',
|
||||
onClick: () => this.openEditStudent(params.row)})
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -883,7 +882,7 @@
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
.table-scroll-wrap :deep(.ivu-table) {
|
||||
height: 100%;
|
||||
}
|
||||
/* 底部栏:分页固定底部 */
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<div class="page-right">
|
||||
<span style="margin-right:12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
v-model="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,40,50]"
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
<!-- 弹窗1:添加学生 -->
|
||||
<Modal v-model="addModalVisible" title="添加学生" width="560">
|
||||
<Form ref="addForm" :model="addForm" :rules="formRules" label-width="90">
|
||||
<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>
|
||||
@@ -87,15 +87,15 @@
|
||||
<Input v-model="addForm.pwd" type="password" placeholder="请输入密码"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="addModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitAddStudent">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗2:编辑学生 -->
|
||||
<Modal v-model="editModalVisible" title="编辑学生" width="560">
|
||||
<Form ref="editForm" :model="editForm" :rules="formRules" label-width="90">
|
||||
<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>
|
||||
@@ -119,18 +119,18 @@
|
||||
<Input v-model="editForm.account"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="editModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitEditStudent">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗3:学生信息导入 -->
|
||||
<Modal v-model="importModalVisible" title="学生信息导入" width="520">
|
||||
<div class="main-contents">
|
||||
<Form ref="UpParmas.datapre" :model="UpParmas.datapre" :label-width="100" inline>
|
||||
<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>
|
||||
<Input type="text" style="width:90%;" v-model="UpParmas.fileName" class="import-input" placeholder="未选中任何文件.." readonly></Input>
|
||||
<Upload class="fr btn"
|
||||
:action="UpParmas.actionUrl"
|
||||
:data="UpParmas.datapre"
|
||||
@@ -140,7 +140,7 @@
|
||||
:before-upload="handleUpload"
|
||||
:on-success="importFile"
|
||||
>
|
||||
<i-button icon="md-add"></i-button>
|
||||
<Button icon="md-add"></Button>
|
||||
</Upload>
|
||||
</FormItem>
|
||||
<FormItem v-if="UpParmas.fileName" style="margin-bottom:10px">
|
||||
@@ -151,8 +151,8 @@
|
||||
|
||||
<Alert show-icon>
|
||||
操作说明:
|
||||
<Icon type="ios-bulb-outline" slot="icon" size="20"></Icon>
|
||||
<template slot="desc" style="font-size: 12px;">
|
||||
<template #icon><Icon type="ios-bulb-outline" size="20"></Icon></template>
|
||||
<template #desc style="font-size: 12px;">
|
||||
请先上传EXCEL文件,若成功则显示导入成功数据,否则显示错误的数据及错误原因;<br>
|
||||
EXCEL文件的格式():工作表(WorkSheet)的名称应设为缺省的[Sheet1];<br>
|
||||
<a @click="MoBanExceldaochu" style="font-size:12px;">点击链接下载[学生信息导入模板.xls]</a>
|
||||
@@ -165,17 +165,17 @@
|
||||
<Icon type="ios-loading" size=30 class="demo-spin-icon-load"></Icon>
|
||||
<div>上传中...</div>
|
||||
</Spin>
|
||||
<div slot="footer">
|
||||
<template #footer><div>
|
||||
<i-Button @click="UpfileModalcloseclick" style="margin-left: 8px">关闭</i-Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗4:学号导入 -->
|
||||
<Modal v-model="stuIdImportModalVisible" title="学生学号导入" width="520">
|
||||
<div class="main-contents">
|
||||
<Form ref="UpParmas2.datapre" :model="UpParmas2.datapre" :label-width="100" inline>
|
||||
<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>
|
||||
<Input type="text" style="width:90%;" v-model="UpParmas2.fileName" class="import-input" placeholder="未选中任何文件.." readonly></Input>
|
||||
<Upload class="fr btn"
|
||||
:action="UpParmas2.actionUrl"
|
||||
:data="UpParmas2.datapre"
|
||||
@@ -185,7 +185,7 @@
|
||||
:before-upload="handleUpload2"
|
||||
:on-success="importFile2"
|
||||
>
|
||||
<i-button icon="md-add"></i-button>
|
||||
<Button icon="md-add"></Button>
|
||||
</Upload>
|
||||
</FormItem>
|
||||
<FormItem v-if="UpParmas2.fileName" style="margin-bottom:10px">
|
||||
@@ -196,8 +196,8 @@
|
||||
|
||||
<Alert show-icon>
|
||||
操作说明:
|
||||
<Icon type="ios-bulb-outline" slot="icon" size="20"></Icon>
|
||||
<template slot="desc" style="font-size: 12px;">
|
||||
<template #icon><Icon type="ios-bulb-outline" size="20"></Icon></template>
|
||||
<template #desc style="font-size: 12px;">
|
||||
请先上传EXCEL文件,若成功则显示导入成功数据,否则显示错误的数据及错误原因;<br>
|
||||
EXCEL文件的格式():工作表(WorkSheet)的名称应设为缺省的[Sheet1];<br>
|
||||
<a @click="MoBanExceldaochu2" style="font-size:12px;">点击链接下载[学生学号信息导入模板.xls]</a>
|
||||
@@ -210,9 +210,9 @@
|
||||
<Icon type="ios-loading" size=30 class="demo-spin-icon-load"></Icon>
|
||||
<div>上传中...</div>
|
||||
</Spin>
|
||||
<div slot="footer">
|
||||
<template #footer><div>
|
||||
<i-Button @click="UpfileModalcloseclick2" style="margin-left: 8px">关闭</i-Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗5:学生调班 -->
|
||||
@@ -236,10 +236,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="moveClassModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitMoveClass">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗6:学生异动 -->
|
||||
@@ -263,23 +263,24 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="changeStatusModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitChangeStatus">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
<!-- 弹窗7:转出学生弹窗 -->
|
||||
<Modal v-model="transferStudentModal" title="转出学生" width="420">
|
||||
<p>确认将选中学生做转出操作?</p>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="transferStudentModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="confirmTransferStudent">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button } from "view-ui-plus";
|
||||
import myTree from "../../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
@@ -500,10 +501,8 @@ export default {
|
||||
align: 'center',
|
||||
width: 80,
|
||||
render: (h, params) => {
|
||||
return h('Button', {
|
||||
props: { type: 'text', icon: 'md-create',type:'large' },
|
||||
on: { click: () => this.openEditStudent(params.row) }
|
||||
})
|
||||
return h(Button, {type: 'text', icon: 'md-create',type:'large',
|
||||
onClick: () => this.openEditStudent(params.row)})
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -866,7 +865,7 @@ export default {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
.table-scroll-wrap :deep(.ivu-table) {
|
||||
height: 100%;
|
||||
}
|
||||
/* 底部栏:分页固定底部 */
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<div class="page-right">
|
||||
<span style="margin-right:12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
v-model="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,40,50]"
|
||||
@@ -71,16 +71,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="changeStatusModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitChangeStatus">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myTree from "../../components/my_tree";
|
||||
import { Button } from "view-ui-plus";
|
||||
import myTree from "../../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: 'StudentManage',
|
||||
@@ -191,10 +192,8 @@
|
||||
align: 'center',
|
||||
width: 80,
|
||||
render: (h, params) => {
|
||||
return h('Button', {
|
||||
props: { type: 'text', icon: 'md-create',type:'large' },
|
||||
on: { click: () => this.openEditModal(params.row) }
|
||||
})
|
||||
return h(Button, {type: 'text', icon: 'md-create',type:'large',
|
||||
onClick: () => this.openEditModal(params.row)})
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -324,7 +323,7 @@
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
.table-scroll-wrap :deep(.ivu-table) {
|
||||
height: 100%;
|
||||
}
|
||||
/* 底部栏:分页固定底部 */
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<div class="page-right">
|
||||
<span style="margin-right:12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
v-model="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,40,50]"
|
||||
@@ -71,15 +71,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="changeStatusModalVisible=false">取消</Button>
|
||||
<Button type="primary" @click="submitChangeStatus()">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button } from "view-ui-plus";
|
||||
import myTree from "../../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
@@ -188,10 +189,8 @@ export default {
|
||||
align: 'center',
|
||||
width: 80,
|
||||
render: (h, params) => {
|
||||
return h('Button', {
|
||||
props: { type: 'text', icon: 'md-create',type:'large' },
|
||||
on: { click: () => this.openEditModal(params.row) }
|
||||
})
|
||||
return h(Button, {type: 'text', icon: 'md-create',type:'large',
|
||||
onClick: () => this.openEditModal(params.row)})
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -317,7 +316,7 @@ export default {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
.table-scroll-wrap :deep(.ivu-table) {
|
||||
height: 100%;
|
||||
}
|
||||
/* 底部栏:分页固定底部 */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="edu-layout-wrap">
|
||||
<Row gutter="10" class="layout-row">
|
||||
<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>
|
||||
@@ -38,7 +38,7 @@
|
||||
</Row>
|
||||
<!-- 新增弹窗 -->
|
||||
<Modal v-model="addModalVisible" title="添加学校" width="520">
|
||||
<Form ref="addFormRef" :model="addForm" :rules="formRules" label-width="90">
|
||||
<Form ref="addFormRef" :model="addForm" :rules="formRules" :label-width="90">
|
||||
<FormItem label="学校名称" prop="schname">
|
||||
<Input size="large" v-model="addForm.schname" placeholder="请输入学校名称" />
|
||||
</FormItem>
|
||||
@@ -58,17 +58,17 @@
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="addModalVisible = false" style="margin-right: 10px">取消</Button>
|
||||
<Button type="primary" @click="submitAdd">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Treeselect from '@riophae/vue-treeselect'
|
||||
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
|
||||
import Treeselect from '@zanmato/vue3-treeselect'
|
||||
import '@zanmato/vue3-treeselect/dist/vue3-treeselect.min.css'
|
||||
import myTree from "../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
style="width:240px"
|
||||
@keyup.enter="handleSearch"
|
||||
>
|
||||
<Icon slot="suffix" type="ios-search" @click="handleSearch" style="cursor:pointer;"></Icon>
|
||||
<template #suffix><Icon type="ios-search" @click="handleSearch" style="cursor:pointer;"></Icon></template>
|
||||
</Input>
|
||||
</div>
|
||||
</div>
|
||||
@@ -41,7 +41,7 @@
|
||||
<div class="pagination-bottom">
|
||||
<span class="total-text">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
v-model="pageNum"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:page-size-opts="[10,20,50]"
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
<!-- 新增/编辑课程弹窗(匹配编辑课程信息截图) -->
|
||||
<Modal v-model="modalVisible" :title="modalTitle" width="580">
|
||||
<Form ref="form" :model="formData" :rules="formRules" label-width="110">
|
||||
<Form ref="form" :model="formData" :rules="formRules" :label-width="110">
|
||||
<FormItem label="课程代码" prop="courseCode">
|
||||
<Input v-model="formData.courseCode" placeholder="请输入课程代码"></Input>
|
||||
</FormItem>
|
||||
@@ -87,16 +87,17 @@
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="modalVisible = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitForm">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
import { Button } from "view-ui-plus";
|
||||
export default {
|
||||
name: 'CourseManage',
|
||||
data() {
|
||||
return {
|
||||
@@ -158,14 +159,10 @@
|
||||
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) }
|
||||
})
|
||||
h(Button, {type: 'text', icon: 'ios-create', size: 'default',
|
||||
onClick: () => this.editRow(params.row, params.index)}),
|
||||
h(Button, {type: 'text', icon: 'ios-trash', size: 'default',
|
||||
onClick: () => this.delRow(params.index)})
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
+22
-22
@@ -12,30 +12,30 @@
|
||||
<div class="btn-container">
|
||||
<draggable
|
||||
v-model="subjectlist"
|
||||
item-key="name"
|
||||
class="drag-wrap"
|
||||
animation="200"
|
||||
:options="{ group: 'people' }"
|
||||
:animation="200"
|
||||
group="people"
|
||||
@start="drag = true"
|
||||
@end="drag = false"
|
||||
:move="getdata1"
|
||||
@update="datadragEnd1"
|
||||
@change="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>
|
||||
<template #item="{ element, index: idx }">
|
||||
<div
|
||||
class="subject-btn"
|
||||
:class="[element.source === 0 ? 'sys-btn' : 'cus-btn', { active: element.enable }]"
|
||||
@click="toggleSelect(idx)"
|
||||
@mouseenter="element.source === 1 && (hoverIndex = idx)"
|
||||
@mouseleave="hoverIndex = null"
|
||||
>
|
||||
<span class="text">{{ element.name }}</span>
|
||||
<div v-if="element.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>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
<!-- 添加自建学科按钮 -->
|
||||
<Button icon="ios-add-outline" class="add-subject-btn" size="large" @click="openAddModal">
|
||||
@@ -58,15 +58,15 @@
|
||||
|
||||
<!-- 新增/编辑弹窗 学科信息 -->
|
||||
<Modal v-model="modalVisible" title="学科信息" width="420">
|
||||
<Form ref="form" :model="formData" :rules="formRules" label-width="90">
|
||||
<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">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="modalVisible = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitForm">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
@@ -132,7 +132,7 @@
|
||||
// 多选切换选中/取消
|
||||
toggleSelect(index) {
|
||||
let submap=this.subjectlist[index];
|
||||
this.$set(this.subjectlist[index], 'enable', !submap.enable);
|
||||
this.subjectlist[index].enable = !submap.enable;
|
||||
const submitData ={
|
||||
id:submap.id,
|
||||
name:submap.name,
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<div class="outer-wrap" style="height:calc(100% - 52px);">
|
||||
<!-- 顶部标签切换 -->
|
||||
<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> -->
|
||||
<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>
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
<!-- 弹窗1:添加学科 -->
|
||||
<Modal v-model="addModalVisible" :title="addFormData.id?'编辑组':'添加组'" width="520">
|
||||
<Form ref="addForm" :model="addFormData" label-width="90">
|
||||
<Form ref="addForm" :model="addFormData" :label-width="90">
|
||||
<FormItem label="组名">
|
||||
<Input v-model="addFormData.groupName" maxlength="20" placeholder="最多可输入20个字符"/>
|
||||
</FormItem>
|
||||
@@ -83,18 +83,18 @@
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="addModalVisible = false">取消</Button>
|
||||
<Button type="primary" @click="submitAdd">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗2:教师批量导入 -->
|
||||
<Modal v-model="importModalVisible" title="批量导入分组信息" width="520">
|
||||
<div class="main-contents">
|
||||
<Form ref="UpParmas.datapre" :model="UpParmas.datapre" :label-width="100" inline>
|
||||
<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>
|
||||
<Input type="text" style="width:90%;" v-model="UpParmas.fileName" class="import-input" placeholder="未选中任何文件.." readonly></Input>
|
||||
<Upload class="fr btn"
|
||||
:action="UpParmas.actionUrl"
|
||||
:data="UpParmas.datapre"
|
||||
@@ -104,7 +104,7 @@
|
||||
:before-upload="handleUpload"
|
||||
:on-success="importFile"
|
||||
>
|
||||
<i-button icon="md-add"></i-button>
|
||||
<Button icon="md-add"></Button>
|
||||
</Upload>
|
||||
</FormItem>
|
||||
<FormItem v-if="UpParmas.fileName" style="margin-bottom:10px">
|
||||
@@ -115,8 +115,8 @@
|
||||
|
||||
<Alert show-icon>
|
||||
操作说明:
|
||||
<Icon type="ios-bulb-outline" slot="icon" size="20"></Icon>
|
||||
<template slot="desc" style="font-size: 12px;">
|
||||
<template #icon><Icon type="ios-bulb-outline" size="20"></Icon></template>
|
||||
<template #desc style="font-size: 12px;">
|
||||
请先上传EXCEL文件,若成功则显示导入成功数据,否则显示错误的数据及错误原因;<br>
|
||||
EXCEL文件的格式():工作表(WorkSheet)的名称应设为缺省的[Sheet1];<br>
|
||||
<a @click="MoBanExceldaochu" style="font-size:12px;">点击链接下载[分组导入模板.xls]</a>
|
||||
@@ -129,12 +129,12 @@
|
||||
<Icon type="ios-loading" size=30 class="demo-spin-icon-load"></Icon>
|
||||
<div>上传中...</div>
|
||||
</Spin>
|
||||
<div slot="footer">
|
||||
<template #footer><div>
|
||||
<i-Button @click="UpfileModalcloseclick" style="margin-left: 8px">关闭</i-Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</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" />
|
||||
<user-check ref="userCheck" :treeData="treeData" :userids="userids" @change="v => (userids = v)" @on-submit="submit" :isDisabled="isAddto" />
|
||||
<user-check ref="userCheck2" :treeData="treeData" :userids="userids2" @change="v => (userids2 = v)" @on-submit="submit2" :isDisabled="isAddto" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<div class="page-fixed-bottom">
|
||||
<span class="total-text">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
v-model="pageNum"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:page-size-opts="[10,20,50]"
|
||||
@@ -166,7 +166,7 @@ export default {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-box >>> .teacher-table {
|
||||
.table-scroll-box :deep(.teacher-table) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
</div>
|
||||
<div class="pagination-wrap">
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
v-model="pageNum"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:page-size-opts="[10,20,50]"
|
||||
@@ -86,7 +86,7 @@
|
||||
|
||||
<!-- 弹窗1:添加教师 -->
|
||||
<Modal v-model="addTeacherModal" title="添加教师" width="540">
|
||||
<Form ref="addTeacherForm" :model="addTeacherFormData" :rules="addTeacherRules" label-width="110">
|
||||
<Form ref="addTeacherForm" :model="addTeacherFormData" :rules="addTeacherRules" :label-width="110">
|
||||
<FormItem label="教师姓名" prop="teacherName">
|
||||
<Input v-model="addTeacherFormData.teacherName" placeholder="请输入老师姓名"></Input>
|
||||
</FormItem>
|
||||
@@ -109,15 +109,15 @@
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="addTeacherModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitAddTeacher">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗2:编辑教师 -->
|
||||
<Modal v-model="editTeacherModal" title="编辑教师" width="540">
|
||||
<Form ref="editTeacherForm" :model="editTeacherFormData" :rules="editTeacherRules" label-width="110">
|
||||
<Form ref="editTeacherForm" :model="editTeacherFormData" :rules="editTeacherRules" :label-width="110">
|
||||
<FormItem label="教师姓名" prop="teacherName">
|
||||
<Input v-model="editTeacherFormData.teacherName"></Input>
|
||||
</FormItem>
|
||||
@@ -137,18 +137,18 @@
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="editTeacherModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitEditTeacher">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗3:教师导入 -->
|
||||
<Modal v-model="importModal" title="教师导入" width="460">
|
||||
<div class="main-contents">
|
||||
<Form ref="UpParmas.datapre" :model="UpParmas.datapre" :label-width="100" inline>
|
||||
<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>
|
||||
<Input type="text" style="width:90%;" v-model="UpParmas.fileName" class="import-input" placeholder="未选中任何文件.." readonly></Input>
|
||||
<Upload class="fr btn"
|
||||
:action="UpParmas.actionUrl"
|
||||
:data="UpParmas.datapre"
|
||||
@@ -158,7 +158,7 @@
|
||||
:before-upload="handleUpload"
|
||||
:on-success="importFile"
|
||||
>
|
||||
<i-button icon="md-add"></i-button>
|
||||
<Button icon="md-add"></Button>
|
||||
</Upload>
|
||||
</FormItem>
|
||||
<FormItem v-if="UpParmas.fileName" style="margin-bottom:10px">
|
||||
@@ -169,8 +169,8 @@
|
||||
|
||||
<Alert show-icon>
|
||||
操作说明:
|
||||
<Icon type="ios-bulb-outline" slot="icon" size="20"></Icon>
|
||||
<template slot="desc" style="font-size: 12px;">
|
||||
<template #icon><Icon type="ios-bulb-outline" size="20"></Icon></template>
|
||||
<template #desc style="font-size: 12px;">
|
||||
请先上传EXCEL文件,若成功则显示导入成功数据,否则显示错误的数据及错误原因;<br>
|
||||
EXCEL文件的格式():工作表(WorkSheet)的名称应设为缺省的[Sheet1];<br>
|
||||
<a @click="MoBanExceldaochu" style="font-size:12px;">点击链接下载[教师导入模板.xls]</a>
|
||||
@@ -183,14 +183,14 @@
|
||||
<Icon type="ios-loading" size=30 class="demo-spin-icon-load"></Icon>
|
||||
<div>上传中...</div>
|
||||
</Spin>
|
||||
<div slot="footer">
|
||||
<template #footer><div>
|
||||
<i-Button @click="UpfileModalcloseclick" style="margin-left: 8px">关闭</i-Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗4:添加子组 -->
|
||||
<Modal v-model="addGroupModal" title="添加子组" width="420">
|
||||
<Form ref="addGroupForm" :model="addGroupFormData" :rules="addGroupRules" label-width="90">
|
||||
<Form ref="addGroupForm" :model="addGroupFormData" :rules="addGroupRules" :label-width="90">
|
||||
<FormItem label="组名称">
|
||||
<Input v-model="addGroupFormData.parentGroupName" disabled></Input>
|
||||
</FormItem>
|
||||
@@ -201,15 +201,15 @@
|
||||
<Input v-model="addGroupFormData.sort"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="addGroupModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitAddGroup">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗5:修改子组 -->
|
||||
<Modal v-model="editGroupModal" title="修改子组" width="420">
|
||||
<Form ref="editGroupForm" :model="editGroupFormData" :rules="editGroupRules" label-width="90">
|
||||
<Form ref="editGroupForm" :model="editGroupFormData" :rules="editGroupRules" :label-width="90">
|
||||
<FormItem label="子组名称" prop="groupName">
|
||||
<Input v-model="editGroupFormData.groupName"></Input>
|
||||
</FormItem>
|
||||
@@ -217,10 +217,10 @@
|
||||
<Input v-model="editGroupFormData.sort"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="editGroupModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitEditGroup">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗6:移动子组 -->
|
||||
@@ -233,10 +233,10 @@
|
||||
<span>移动至:</span>
|
||||
<my-tree :treeData="treeData" @on-tree-click="movetreeLink"></my-tree>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="moveGroupModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="confirmMoveGroup">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗7:批量删除确认 -->
|
||||
@@ -244,10 +244,10 @@
|
||||
<Alert type="warning" show-icon>
|
||||
确定是否删除教师?<br/>删除后将不可恢复。
|
||||
</Alert>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="batchDeleteModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="error" @click="confirmBatchDelete">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗8:移动教师弹窗 -->
|
||||
@@ -294,15 +294,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="moveTeacherModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitMoveTeacher">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗9:【设置教师的状态】 匹配设计图 -->
|
||||
<Modal v-model="setStatusModal" title="设置教师的状态" width="380">
|
||||
<Form ref="statusForm" :model="statusFormData" label-width="120">
|
||||
<Form ref="statusForm" :model="statusFormData" :label-width="120">
|
||||
<FormItem label="选择设置状态">
|
||||
<RadioGroup v-model="statusFormData.status">
|
||||
<Radio label="0">正常</Radio>
|
||||
@@ -310,25 +310,26 @@
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="setStatusModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="submitSetStatus">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 弹窗10:转出教师弹窗 -->
|
||||
<Modal v-model="transferTeacherModal" title="转出教师" width="420">
|
||||
<p>确认将选中教师做转出操作?转出后不在本校编制内</p>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="transferTeacherModal = false" style="margin-right:10px">取消</Button>
|
||||
<Button type="primary" @click="confirmTransferTeacher">确定</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myTree from "../../components/my_tree";
|
||||
import { Button } from "view-ui-plus";
|
||||
import myTree from "../../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: 'TeacherInfoManage',
|
||||
@@ -401,10 +402,8 @@ export default {
|
||||
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) }
|
||||
})
|
||||
return h(Button, {type: 'text', icon: 'md-create', size: 'large',
|
||||
onClick: () => this.editSingleTeacher(params.row, params.index)})
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -941,7 +940,7 @@ export default {
|
||||
gap: 8px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.tree-sidebar >>> .ivu-tree {
|
||||
.tree-sidebar :deep(.ivu-tree) {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 8px;
|
||||
|
||||
@@ -42,18 +42,18 @@
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="teacherModalVisible = false">取消</Button>
|
||||
<Button type="primary" @click="submitSelectTeacher">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
|
||||
<!-- 批量导入弹窗 -->
|
||||
<Modal v-model="importModalVisible" title="批量导入任教信息" width="520">
|
||||
<div class="main-contents">
|
||||
<Form ref="UpParmas.datapre" :model="UpParmas.datapre" :label-width="100" inline>
|
||||
<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>
|
||||
<Input type="text" style="width:90%;" v-model="UpParmas.fileName" class="import-input" placeholder="未选中任何文件.." readonly></Input>
|
||||
<Upload class="fr btn"
|
||||
:action="UpParmas.actionUrl"
|
||||
:data="UpParmas.datapre"
|
||||
@@ -63,7 +63,7 @@
|
||||
:before-upload="handleUpload"
|
||||
:on-success="importFile"
|
||||
>
|
||||
<i-button icon="md-add"></i-button>
|
||||
<Button icon="md-add"></Button>
|
||||
</Upload>
|
||||
</FormItem>
|
||||
<FormItem v-if="UpParmas.fileName" style="margin-bottom:10px">
|
||||
@@ -74,8 +74,8 @@
|
||||
|
||||
<Alert show-icon>
|
||||
操作说明:
|
||||
<Icon type="ios-bulb-outline" slot="icon" size="20"></Icon>
|
||||
<template slot="desc" style="font-size: 12px;">
|
||||
<template #icon><Icon type="ios-bulb-outline" size="20"></Icon></template>
|
||||
<template #desc style="font-size: 12px;">
|
||||
请先上传EXCEL文件,若成功则显示导入成功数据,否则显示错误的数据及错误原因;<br>
|
||||
EXCEL文件的格式():工作表(WorkSheet)的名称应设为缺省的[Sheet1];<br>
|
||||
<a @click="MoBanExceldaochu" style="font-size:12px;">点击链接下载[任教导入模板.xls]</a>
|
||||
@@ -88,14 +88,15 @@
|
||||
<Icon type="ios-loading" size=30 class="demo-spin-icon-load"></Icon>
|
||||
<div>上传中...</div>
|
||||
</Spin>
|
||||
<div slot="footer">
|
||||
<template #footer><div>
|
||||
<i-Button @click="UpfileModalcloseclick" style="margin-left: 8px">关闭</i-Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button } from "view-ui-plus";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: 'TeachManage',
|
||||
@@ -380,11 +381,9 @@ export default {
|
||||
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) }
|
||||
})
|
||||
return h(Button, {type: 'text', icon: 'ios-refresh', size: 'large',
|
||||
onClick: () => this.handleResetRow(params.index),
|
||||
attrs: { title: '重置本行所有任教' }})
|
||||
}
|
||||
}];
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<div class="page-area">
|
||||
<span style="margin-right: 12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
v-model="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,40]"
|
||||
@@ -67,16 +67,17 @@
|
||||
<my-tree :treeData="groupTreeData" @on-tree-click="treeLink"></my-tree>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="transferModalVisible = false">取消</Button>
|
||||
<Button type="primary" @click="submitTransfer">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myTree from "../components/my_tree";
|
||||
import { Button } from "view-ui-plus";
|
||||
import myTree from "../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
name: 'TeacherTransferPage',
|
||||
@@ -159,10 +160,8 @@
|
||||
align: 'center',
|
||||
width: 100,
|
||||
render: (h, params) => {
|
||||
return h('Button', {
|
||||
props: { type: 'text' },
|
||||
on: { click: () => this.openTransferModal(params.row) }
|
||||
},'转入')
|
||||
return h(Button, {type: 'text',
|
||||
onClick: () => this.openTransferModal(params.row)},'转入')
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -297,7 +296,7 @@
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
.table-scroll-wrap :deep(.ivu-table) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<div class="page-area">
|
||||
<span style="margin-right: 12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
v-model="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,40]"
|
||||
@@ -74,15 +74,16 @@
|
||||
<my-tree :treeData="targetTreeData" @on-tree-click="treeLink"></my-tree>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" align="right">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="moveModalVisible = false">取消</Button>
|
||||
<Button type="primary" @click="submitMove">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Button } from "view-ui-plus";
|
||||
import myTree from "../../components/my_tree";
|
||||
import { self_viewport } from "@/mixins/self_viewport";
|
||||
export default {
|
||||
@@ -183,10 +184,8 @@ export default {
|
||||
align: 'center',
|
||||
width: 100,
|
||||
render: (h, params) => {
|
||||
return h('Button', {
|
||||
props: { type: 'text' },
|
||||
on: { click: () => this.openMoveModal(params.row) }
|
||||
},'转入')
|
||||
return h(Button, {type: 'text',
|
||||
onClick: () => this.openMoveModal(params.row)},'转入')
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -320,7 +319,7 @@ export default {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
.table-scroll-wrap :deep(.ivu-table) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
<div class="page-area">
|
||||
<span style="margin-right: 12px">共 {{ total }} 条</span>
|
||||
<Page
|
||||
:current.sync="pageNum"
|
||||
v-model="pageNum"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-size-opts="[10,20,40]"
|
||||
@@ -81,15 +81,14 @@
|
||||
: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">
|
||||
<template #footer><div align="right">
|
||||
<Button @click="moveModalVisible = false">取消</Button>
|
||||
<Button type="primary" @click="submitMove">提交</Button>
|
||||
</div>
|
||||
</div></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
@@ -265,7 +264,7 @@ export default {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.table-scroll-wrap >>> .ivu-table {
|
||||
.table-scroll-wrap :deep(.ivu-table) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_BASE_HOST: string;
|
||||
readonly VITE_SSO_HOST: string;
|
||||
readonly VITE_SERVICE_HOST: string;
|
||||
readonly VITE_IS_MOCK: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
},
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
"strict": false,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"allowJs": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"types": ["vite/client"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import path from "path";
|
||||
import { createHtmlPlugin } from "vite-plugin-html";
|
||||
|
||||
/**
|
||||
* 构建基线对齐 NoticeFront(云海子应用前端接入规范 v1.12):
|
||||
* Vue3 + TS + view-ui-plus(1.3.24) + Vite;主题/皮肤/图标由 /static 通道下发。
|
||||
*/
|
||||
export default defineConfig(({ mode }) => {
|
||||
const root = process.cwd();
|
||||
|
||||
return {
|
||||
plugins: [
|
||||
vue(),
|
||||
createHtmlPlugin({
|
||||
minify: true,
|
||||
pages: [
|
||||
{
|
||||
entry: "src/main.ts",
|
||||
template: "index.html",
|
||||
filename: "index.html",
|
||||
injectOptions: {
|
||||
data: {
|
||||
title: "学校管理",
|
||||
injectScript: ``,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(root, "src"),
|
||||
"@public": path.resolve(root, "public"),
|
||||
},
|
||||
extensions: [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json", ".vue"],
|
||||
},
|
||||
server: {
|
||||
host: "localhost",
|
||||
port: 8088,
|
||||
open: false,
|
||||
proxy: {
|
||||
// 本地后端:serviceUrl 在 dev 下为空 → /api/* 同源相对,由本代理转发
|
||||
"/api": {
|
||||
target: process.env.YH_API_PROXY_TARGET || "http://localhost:8101",
|
||||
changeOrigin: true,
|
||||
},
|
||||
// 主题通道本地联调:默认线上通道,联调本地通道源用
|
||||
// YH_THEME_PROXY_TARGET=http://localhost:9527 npm run dev
|
||||
"/static": {
|
||||
target: process.env.YH_THEME_PROXY_TARGET || "http://base.yunhaixingtong.com",
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
base: "./",
|
||||
build: {
|
||||
target: "modules",
|
||||
outDir: "dist",
|
||||
assetsDir: "assets",
|
||||
sourcemap: false,
|
||||
minify: "esbuild",
|
||||
chunkSizeWarningLimit: 1500,
|
||||
cssTarget: "chrome61",
|
||||
rollupOptions: {
|
||||
input: {
|
||||
main: path.resolve(root, "index.html"),
|
||||
},
|
||||
output: {
|
||||
chunkFileNames: "static/js/[name]-[hash].js",
|
||||
entryFileNames: "static/js/[name]-[hash].js",
|
||||
assetFileNames: (assetInfo: any) => {
|
||||
if (assetInfo.type === "asset" && /\.(jpe?g|png|gif|svg)$/i.test(assetInfo.name)) {
|
||||
return "static/img/[name].[hash][ext]";
|
||||
}
|
||||
if (assetInfo.type === "asset" && /\.(ttf|woff|woff2|eot)$/i.test(assetInfo.name)) {
|
||||
return "static/fonts/[name].[hash][ext]";
|
||||
}
|
||||
return "static/[ext]/[name]-[hash].[ext]";
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
-112
@@ -1,112 +0,0 @@
|
||||
const path = require("path");
|
||||
function resolve(dir) {
|
||||
return path.join(__dirname, dir);
|
||||
}
|
||||
|
||||
const isDev = process.env.NODE_ENV !== "production";
|
||||
|
||||
module.exports = {
|
||||
publicPath: "./", //部署应用时的根路径(默认'/'),也可用相对路径(存在使用限制)
|
||||
outputDir: "dist", //运行时生成的生产环境构建文件的目录(默认'dist',构建之前会被清除)
|
||||
assetsDir: "", //静态资源目录(js、css、img、fonts),相对outputDir的目录(默认'')
|
||||
indexPath: "index.html", //指定生成index.html的输出路径(相对outputDir)也可以是绝对路径
|
||||
lintOnSave: false, //是否开启ESlint(保存时检查)
|
||||
configureWebpack: {
|
||||
//配置路径
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": resolve("/src"),
|
||||
"@assets": resolve("/src/assets"),
|
||||
"@public": resolve("/public")
|
||||
},
|
||||
extensions: [".js", ".json", ".css", ".scss", ".vue"]
|
||||
},
|
||||
externals: {
|
||||
//采用地址栏的方式来引用
|
||||
vue: "Vue",
|
||||
axios: "axios"
|
||||
}
|
||||
// entry: {
|
||||
// app: ["@babel/polyfill", "./src/main.js"],
|
||||
// },
|
||||
},
|
||||
productionSourceMap: false, //生产环境是否生成 sourceMap 文件
|
||||
pages: {
|
||||
//pages里配置的路径和文件名在你的文档目录必须存在,否则启动服务会报错
|
||||
index: {
|
||||
//除了 entry 之外都是可选的
|
||||
entry: "src/main.js", //page的主入口
|
||||
template: "public/index.html", //模板来源
|
||||
filename: "index.html", //在 dist/index.html 的输出
|
||||
//title在template中使用:<title><%=htmlWebpackPlugin.options.title%></title>
|
||||
title: "beschool",
|
||||
chunks: ["chunk-vendors", "chunk-common", "index"]
|
||||
// 在这个页面中包含的块,默认情况下会包含,提取出来的通用 chunk 和 vendor chunk
|
||||
}
|
||||
//subpage: 'src/main.js'
|
||||
//官方解释:当使用只有入口的字符串格式时,模板会被推导为public/subpage.html
|
||||
//若找不到就回退到public/index.html,输出文件名会被推导为subpage.html
|
||||
},
|
||||
css: {
|
||||
extract: !isDev, //是否使用css分离插件 ExtractTextPlugin
|
||||
sourceMap: isDev, //开启 CSS source maps
|
||||
// modules: false, //启用CSS modules for all css / pre-processor files.
|
||||
requireModuleExtension: true, //与modules相反
|
||||
loaderOptions: {
|
||||
//css预设器配置项
|
||||
sass: {
|
||||
// prependData: `@import "@assets/styles/varible.scss";`,
|
||||
}
|
||||
/* postcss: {
|
||||
plugins: [
|
||||
require('postcss-pxtorem')({
|
||||
rootValue: 37.5, // 换算的基数
|
||||
selectorBlackList: [], // 忽略转换正则匹配项
|
||||
propList: ['*'],
|
||||
}),
|
||||
]
|
||||
} */
|
||||
}
|
||||
},
|
||||
|
||||
devServer: {
|
||||
//环境配置
|
||||
host: "localhost",
|
||||
port: 8088,
|
||||
https: false, //是否开启https
|
||||
hotOnly: true, //是否配置热更新
|
||||
open: true, //配置自动启动浏览器
|
||||
// 主题通道 dev 代理(A 类接入 §2.2 第一步):
|
||||
// 本地开发时 /static/* 兜到主题通道(默认线上通道),联调本地通道源可覆盖:
|
||||
// YH_THEME_PROXY_TARGET=http://localhost:9527 npm run dev
|
||||
// 生产与通道同源,不依赖本代理。
|
||||
proxy: {
|
||||
"/static": {
|
||||
target: process.env.YH_THEME_PROXY_TARGET || "http://base.yunhaixingtong.com",
|
||||
changeOrigin: true,
|
||||
ws: true
|
||||
}
|
||||
// 原有业务接口代理示例(按需启用):
|
||||
// '/api': {
|
||||
// target: 'http://basedebug.bestsch.com/BschHome',
|
||||
// ws: true, //是否跨域
|
||||
// changeOrigin: true,
|
||||
// // pathRewrite: { '^/api': '' }
|
||||
// }
|
||||
},
|
||||
overlay: {
|
||||
//关闭eslint
|
||||
warnings: false,
|
||||
errors: false
|
||||
}
|
||||
},
|
||||
pluginOptions: {
|
||||
// 第三方插件配置
|
||||
// ...
|
||||
},
|
||||
transpileDependencies: [
|
||||
"view-design"
|
||||
// "vue-grid-layout",
|
||||
// "vue-grid-layout.common.js"
|
||||
] //ie兼容相关
|
||||
};
|
||||
Reference in New Issue
Block a user