From 9ba591e7a1599d493e87fb99bade0f6fe6db4602 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Mon, 22 Jun 2026 22:39:56 +0800 Subject: [PATCH] feat: add platform school admin management --- src/api/platformAdmin.js | 77 +++++++ src/api/schoolAdmin.js | 171 ++++++++++++++ src/layout/components/Navbar.vue | 136 +++++++---- src/layout/components/Sidebar/index.vue | 14 +- src/layout/index.vue | 9 +- src/permission.js | 16 +- src/plugins/auth.js | 15 +- src/router/index.js | 134 ++++++++++- src/utils/chinaRegions.js | 117 ++++++++++ src/views/index.vue | 132 +++++++++-- src/views/platformAdmin/school/index.vue | 208 +++++++++++++++++ src/views/platformAdmin/schoolAdmin/index.vue | 176 +++++++++++++++ src/views/schoolAdmin/admin-theme.scss | 212 ++++++++++++++++++ src/views/schoolAdmin/class/index.vue | 122 ++++++++++ src/views/schoolAdmin/faculty/index.vue | 109 +++++++++ src/views/schoolAdmin/major/index.vue | 123 ++++++++++ src/views/schoolAdmin/school/index.vue | 85 +++++++ src/views/schoolAdmin/student/index.vue | 124 ++++++++++ src/views/schoolAdmin/teacher/index.vue | 104 +++++++++ 19 files changed, 1999 insertions(+), 85 deletions(-) create mode 100644 src/api/platformAdmin.js create mode 100644 src/api/schoolAdmin.js create mode 100644 src/utils/chinaRegions.js create mode 100644 src/views/platformAdmin/school/index.vue create mode 100644 src/views/platformAdmin/schoolAdmin/index.vue create mode 100644 src/views/schoolAdmin/admin-theme.scss create mode 100644 src/views/schoolAdmin/class/index.vue create mode 100644 src/views/schoolAdmin/faculty/index.vue create mode 100644 src/views/schoolAdmin/major/index.vue create mode 100644 src/views/schoolAdmin/school/index.vue create mode 100644 src/views/schoolAdmin/student/index.vue create mode 100644 src/views/schoolAdmin/teacher/index.vue diff --git a/src/api/platformAdmin.js b/src/api/platformAdmin.js new file mode 100644 index 0000000..135266c --- /dev/null +++ b/src/api/platformAdmin.js @@ -0,0 +1,77 @@ +import request from "@/utils/request"; + +export function getPlatformSchools(params) { + return request({ + url: "/api/platform-admin/schools", + method: "get", + params, + }); +} + +export function getPlatformSchool(id) { + return request({ + url: `/api/platform-admin/schools/${id}`, + method: "get", + }); +} + +export function addPlatformSchool(data) { + return request({ + url: "/api/platform-admin/schools", + method: "post", + data, + }); +} + +export function updatePlatformSchool(id, data) { + return request({ + url: `/api/platform-admin/schools/${id}`, + method: "put", + data, + }); +} + +export function deletePlatformSchool(id) { + return request({ + url: `/api/platform-admin/schools/${id}`, + method: "delete", + }); +} + +export function getPlatformSchoolAdmins(params) { + return request({ + url: "/api/platform-admin/school-admins", + method: "get", + params, + }); +} + +export function getPlatformSchoolAdmin(id) { + return request({ + url: `/api/platform-admin/school-admins/${id}`, + method: "get", + }); +} + +export function addPlatformSchoolAdmin(data) { + return request({ + url: "/api/platform-admin/school-admins", + method: "post", + data, + }); +} + +export function updatePlatformSchoolAdmin(id, data) { + return request({ + url: `/api/platform-admin/school-admins/${id}`, + method: "put", + data, + }); +} + +export function deletePlatformSchoolAdmin(id) { + return request({ + url: `/api/platform-admin/school-admins/${id}`, + method: "delete", + }); +} diff --git a/src/api/schoolAdmin.js b/src/api/schoolAdmin.js new file mode 100644 index 0000000..8373e49 --- /dev/null +++ b/src/api/schoolAdmin.js @@ -0,0 +1,171 @@ +import request from "@/utils/request"; + +export function getAdminSchool() { + return request({ + url: "/api/school-admin/school", + method: "get", + }); +} + +export function updateAdminSchool(data) { + return request({ + url: "/api/school-admin/school", + method: "put", + data, + }); +} + +export function getAdminFaculties(params) { + return request({ + url: "/api/school-admin/faculties", + method: "get", + params, + }); +} + +export function addAdminFaculty(data) { + return request({ + url: "/api/school-admin/faculties", + method: "post", + data, + }); +} + +export function updateAdminFaculty(id, data) { + return request({ + url: `/api/school-admin/faculties/${id}`, + method: "put", + data, + }); +} + +export function deleteAdminFaculty(id) { + return request({ + url: `/api/school-admin/faculties/${id}`, + method: "delete", + }); +} + +export function getAdminMajors(params) { + return request({ + url: "/api/school-admin/majors", + method: "get", + params, + }); +} + +export function addAdminMajor(data) { + return request({ + url: "/api/school-admin/majors", + method: "post", + data, + }); +} + +export function updateAdminMajor(id, data) { + return request({ + url: `/api/school-admin/majors/${id}`, + method: "put", + data, + }); +} + +export function deleteAdminMajor(id) { + return request({ + url: `/api/school-admin/majors/${id}`, + method: "delete", + }); +} + +export function getAdminClasses(params) { + return request({ + url: "/api/school-admin/classes", + method: "get", + params, + }); +} + +export function addAdminClass(data) { + return request({ + url: "/api/school-admin/classes", + method: "post", + data, + }); +} + +export function updateAdminClass(id, data) { + return request({ + url: `/api/school-admin/classes/${id}`, + method: "put", + data, + }); +} + +export function deleteAdminClass(id) { + return request({ + url: `/api/school-admin/classes/${id}`, + method: "delete", + }); +} + +export function getAdminTeachers(params) { + return request({ + url: "/api/school-admin/teachers", + method: "get", + params, + }); +} + +export function addAdminTeacher(data) { + return request({ + url: "/api/school-admin/teachers", + method: "post", + data, + }); +} + +export function updateAdminTeacher(id, data) { + return request({ + url: `/api/school-admin/teachers/${id}`, + method: "put", + data, + }); +} + +export function deleteAdminTeacher(id) { + return request({ + url: `/api/school-admin/teachers/${id}`, + method: "delete", + }); +} + +export function getAdminStudents(params) { + return request({ + url: "/api/school-admin/students", + method: "get", + params, + }); +} + +export function addAdminStudent(data) { + return request({ + url: "/api/school-admin/students", + method: "post", + data, + }); +} + +export function updateAdminStudent(id, data) { + return request({ + url: `/api/school-admin/students/${id}`, + method: "put", + data, + }); +} + +export function deleteAdminStudent(id) { + return request({ + url: `/api/school-admin/students/${id}`, + method: "delete", + }); +} diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue index 4b94b77..6a0ab57 100644 --- a/src/layout/components/Navbar.vue +++ b/src/layout/components/Navbar.vue @@ -4,11 +4,11 @@ 电商互联网产品开发实训系统 数 字 营 销 实 训 系 统 - 教 师 端 -
- -
+
+ +
@@ -83,19 +83,32 @@ import useSettingsStore from "@/store/modules/settings"; import * as indexApi from "@/api/teacher"; const { proxy } = getCurrentInstance(); const router = useRouter(); -const appStore = useAppStore(); -const userStore = useUserStore(); -const settingsStore = useSettingsStore(); -const showModel = ref(false); -const form = ref({}); +const appStore = useAppStore(); +const userStore = useUserStore(); +const settingsStore = useSettingsStore(); +const showModel = ref(false); +const form = ref({}); +const role = computed(() => Number(userStore.userInfo.roleId)); const mentList = ref([ - { - name: "首页", - path: "/index", - }, - { - name: "实验报告", - path: "/report/index", + { + name: "首页", + path: "/index", + }, + { + name: "学校管理", + path: "/platform-schools/index", + role: 1, + activePrefix: "/platform-schools", + }, + { + name: "学校管理员", + path: "/platform-school-admins/index", + role: 1, + activePrefix: "/platform-school-admins", + }, + { + name: "实验报告", + path: "/report/index", role: 4, }, { @@ -151,21 +164,43 @@ function logout() { function setLayout() { showModel.value = true; } -const go = (item) => { - activement.value = item; - router.push(item.path); -}; -// 根据角色显示菜单 -const roleList = computed(() => { - return mentList.value.filter((item) => { - if (!item.role || item.name === "首页" || item.name === "AI学情分析") return true; - return item.role == userStore.userInfo.roleId; - }); -}); +const go = (item) => { + activement.value = item; + router.push(item.path); +}; +const isActive = (item) => { + return item.activePrefix ? router.currentRoute.value.path.startsWith(item.activePrefix) : item.path === router.currentRoute.value.path; +}; +// 根据角色显示菜单 +const roleList = computed(() => { + const currentRole = role.value; + return mentList.value.filter((item) => { + if (currentRole === 1) { + return item.path === "/index" || item.role === 1; + } + if (currentRole === 2) { + return item.path === "/index"; + } + if (!item.role || item.path === "/index" || item.path === "/analysis/index") return true; + return item.role == currentRole; + }); +}); // 获取用户详情 -const getUserInfo = () => { - indexApi - .getInfo({ userId: userStore.userInfo.userId }) +const getUserInfo = () => { + if (role.value === 1) { + form.value = { + username: userStore.userInfo.name, + name: userStore.userInfo.username, + schoolFacultyId: "平台级账号", + schoolMajorId: "平台级账号", + schoolClassId: "无", + password: "******", + passwords: "", + }; + return; + } + indexApi + .getInfo({ userId: userStore.userInfo.userId }) .then((res) => { form.value = res.data; }) @@ -262,18 +297,33 @@ onMounted(() => { font-size: 20px; color: #fff; font-weight: bold; - display: flex; - gap: 30px; - .el-ment-item { - cursor: pointer; - &:hover { - color: #409eff; - } - } - .el-ment-item-active { - color: #409eff; - } - } + display: flex; + gap: 18px; + align-items: center; + white-space: nowrap; + .el-ment-item { + padding: 6px 16px; + border: 1px solid transparent; + border-radius: 999px; + cursor: pointer; + line-height: 1; + transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease; + &:hover { + color: #9ee7ff; + border-color: rgba(0, 170, 255, 0.42); + background: rgba(0, 124, 204, 0.18); + } + } + .el-ment-item-active { + color: #9ee7ff; + border-color: rgba(0, 170, 255, 0.68); + background: linear-gradient(90deg, rgba(0, 143, 254, 0.32), rgba(10, 92, 134, 0.2)); + box-shadow: inset 0 0 12px rgba(0, 170, 255, 0.12); + } + &.platform-nav { + gap: 14px; + } + } .right-menu { float: right; height: 100%; diff --git a/src/layout/components/Sidebar/index.vue b/src/layout/components/Sidebar/index.vue index 922b8ba..a4fdfb1 100644 --- a/src/layout/components/Sidebar/index.vue +++ b/src/layout/components/Sidebar/index.vue @@ -24,7 +24,7 @@ import useAppStore from "@/store/modules/app"; import * as indexApi from "@/api/teacher"; import useSettingsStore from "@/store/modules/settings"; import usePermissionStore from "@/store/modules/permission"; -import { constantRoutes, dynamicRoutes, teacherRoutes } from "@/router/index.js"; +import { constantRoutes, dynamicRoutes, teacherRoutes, platformAdminRoutes, schoolAdminRoutes } from "@/router/index.js"; import useUserStore from "@/store/modules/user"; const { proxy } = getCurrentInstance(); const userStore = useUserStore(); @@ -319,10 +319,14 @@ function excludeRoutesByMetaTitle(routes, excludeTitles) { return result; }, []); } -const getTaskList = () => { - if (userStore.userInfo.roleId != 3) { - indexApi.getTaskList({ classId: userStore.userInfo.classId }).then((res) => { - const disabledTitles = processModuleStatus(groupAndSortModules(res.data)).disabledParents; +const getTaskList = () => { + if (userStore.userInfo.roleId == 1) { + sidebarRouters.value = [...constantRoutes, ...platformAdminRoutes]; + } else if (userStore.userInfo.roleId == 2) { + sidebarRouters.value = [...constantRoutes, ...schoolAdminRoutes]; + } else if (userStore.userInfo.roleId != 3) { + indexApi.getTaskList({ classId: userStore.userInfo.classId }).then((res) => { + const disabledTitles = processModuleStatus(groupAndSortModules(res.data)).disabledParents; console.log(processModuleStatus(groupAndSortModules(res.data))); proxy.$cache.session.setJSON("disabledChildren", processModuleStatus(groupAndSortModules(res.data)).disabledChildren); proxy.$cache.session.setJSON("disabledTitles", disabledTitles); diff --git a/src/layout/index.vue b/src/layout/index.vue index 76abec3..e6d4979 100644 --- a/src/layout/index.vue +++ b/src/layout/index.vue @@ -4,8 +4,8 @@
- -
+ +
@@ -22,14 +22,15 @@ import { getUserInfo } from "@/utils/auth"; import useAppStore from "@/store/modules/app"; import useSettingsStore from "@/store/modules/settings"; -const role = ref(JSON.parse(getUserInfo()).roleId); +const role = ref(Number(JSON.parse(getUserInfo()).roleId)); const settingsStore = useSettingsStore(); const theme = computed(() => settingsStore.theme); const sideTheme = computed(() => settingsStore.sideTheme); const sidebar = computed(() => useAppStore().sidebar); const device = computed(() => useAppStore().device); const needTagsView = computed(() => settingsStore.tagsView); -const fixedHeader = computed(() => settingsStore.fixedHeader); +const fixedHeader = computed(() => settingsStore.fixedHeader); +const useTopNavbarOnly = computed(() => role.value === 1); const classObj = computed(() => ({ hideSidebar: !sidebar.value.opened, diff --git a/src/permission.js b/src/permission.js index ca74d49..f071250 100644 --- a/src/permission.js +++ b/src/permission.js @@ -23,11 +23,17 @@ const whiteList = ["/login", "/register"]; router.beforeEach((to, from, next) => { NProgress.start(); if (getToken()) { - if (to.path === "/login") { - if (JSON.parse(getUserInfo()).roleId == 3) { - next({ path: "/index" }); - NProgress.done(); - } else if (JSON.parse(getUserInfo()).roleId == 4) { + if (to.path === "/login") { + if (JSON.parse(getUserInfo()).roleId == 1) { + next({ path: "/index" }); + NProgress.done(); + } else if (JSON.parse(getUserInfo()).roleId == 2) { + next({ path: "/index" }); + NProgress.done(); + } else if (JSON.parse(getUserInfo()).roleId == 3) { + next({ path: "/index" }); + NProgress.done(); + } else if (JSON.parse(getUserInfo()).roleId == 4) { next({ path: "/index" }); NProgress.done(); } diff --git a/src/plugins/auth.js b/src/plugins/auth.js index eb434e8..718f643 100644 --- a/src/plugins/auth.js +++ b/src/plugins/auth.js @@ -12,10 +12,17 @@ function authPermission(permission) { } } -function authRole(role) { - const super_admin = "admin"; - const roles = [parseFloat(JSON.parse(getUserInfo()).roleId) ==3 ? 'teacher':'student'] - if (role && role.length > 0) { +function authRole(role) { + const super_admin = "admin"; + const roleMap = { + 1: "platformAdmin", + 2: "schoolAdmin", + 3: "teacher", + 4: "student", + }; + const roleId = Number(JSON.parse(getUserInfo()).roleId); + const roles = [roleMap[roleId]].filter(Boolean); + if (role && role.length > 0) { return roles.some(v => { return super_admin === v || v === role }) diff --git a/src/router/index.js b/src/router/index.js index db67369..9576c03 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -388,7 +388,7 @@ export const dynamicRoutes = [ }, ]; // 教师端路由 -export const teacherRoutes = [ +export const teacherRoutes = [ { path: "/school", component: Layout, @@ -507,10 +507,134 @@ export const teacherRoutes = [ }, ], }, -]; -const router = createRouter({ - history: createWebHistory(), - routes: [...constantRoutes, ...dynamicRoutes, ...teacherRoutes], +]; +export const platformAdminRoutes = [ + { + path: "/platform-schools", + component: Layout, + redirect: "/platform-schools/index", + roles: ["platformAdmin"], + meta: { title: "学校管理", icon: "学校", affix: true }, + children: [ + { + path: "index", + component: () => import("@/views/platformAdmin/school/index.vue"), + name: "platformSchools", + meta: { title: "学校管理", icon: "学校", affix: true }, + }, + ], + }, + { + path: "/platform-school-admins", + component: Layout, + redirect: "/platform-school-admins/index", + roles: ["platformAdmin"], + meta: { title: "学校管理员", icon: "用户", affix: true }, + children: [ + { + path: "index", + component: () => import("@/views/platformAdmin/schoolAdmin/index.vue"), + name: "platformSchoolAdmins", + meta: { title: "学校管理员", icon: "用户", affix: true }, + }, + ], + }, +]; +export const schoolAdminRoutes = [ + { + path: "/admin-school", + component: Layout, + redirect: "/admin-school/index", + roles: ["schoolAdmin"], + meta: { title: "学校管理", icon: "学校", affix: true }, + children: [ + { + path: "index", + component: () => import("@/views/schoolAdmin/school/index.vue"), + name: "adminSchool", + meta: { title: "学校管理", icon: "学校", affix: true }, + }, + ], + }, + { + path: "/admin-faculty", + component: Layout, + redirect: "/admin-faculty/index", + roles: ["schoolAdmin"], + meta: { title: "院系管理", icon: "院系管理", affix: true }, + children: [ + { + path: "index", + component: () => import("@/views/schoolAdmin/faculty/index.vue"), + name: "adminFaculty", + meta: { title: "院系管理", icon: "院系管理", affix: true }, + }, + ], + }, + { + path: "/admin-major", + component: Layout, + redirect: "/admin-major/index", + roles: ["schoolAdmin"], + meta: { title: "专业管理", icon: "专业管理", affix: true }, + children: [ + { + path: "index", + component: () => import("@/views/schoolAdmin/major/index.vue"), + name: "adminMajor", + meta: { title: "专业管理", icon: "专业管理", affix: true }, + }, + ], + }, + { + path: "/admin-class", + component: Layout, + redirect: "/admin-class/index", + roles: ["schoolAdmin"], + meta: { title: "班级管理", icon: "班级管理", affix: true }, + children: [ + { + path: "index", + component: () => import("@/views/schoolAdmin/class/index.vue"), + name: "adminClass", + meta: { title: "班级管理", icon: "班级管理", affix: true }, + }, + ], + }, + { + path: "/admin-teacher", + component: Layout, + redirect: "/admin-teacher/index", + roles: ["schoolAdmin"], + meta: { title: "教师管理", icon: "教师管理", affix: true }, + children: [ + { + path: "index", + component: () => import("@/views/schoolAdmin/teacher/index.vue"), + name: "adminTeacher", + meta: { title: "教师管理", icon: "教师管理", affix: true }, + }, + ], + }, + { + path: "/admin-student", + component: Layout, + redirect: "/admin-student/index", + roles: ["schoolAdmin"], + meta: { title: "学生管理", icon: "学生管理", affix: true }, + children: [ + { + path: "index", + component: () => import("@/views/schoolAdmin/student/index.vue"), + name: "adminStudent", + meta: { title: "学生管理", icon: "学生管理", affix: true }, + }, + ], + }, +]; +const router = createRouter({ + history: createWebHistory(), + routes: [...constantRoutes, ...dynamicRoutes, ...teacherRoutes, ...platformAdminRoutes, ...schoolAdminRoutes], scrollBehavior(to, from, savedPosition) { if (savedPosition) { return savedPosition; diff --git a/src/utils/chinaRegions.js b/src/utils/chinaRegions.js new file mode 100644 index 0000000..ded0eee --- /dev/null +++ b/src/utils/chinaRegions.js @@ -0,0 +1,117 @@ +export const chinaRegions = [ + { province: "北京市", cities: ["北京市"] }, + { province: "天津市", cities: ["天津市"] }, + { + province: "河北省", + cities: ["石家庄市", "唐山市", "秦皇岛市", "邯郸市", "邢台市", "保定市", "张家口市", "承德市", "沧州市", "廊坊市", "衡水市"], + }, + { + province: "山西省", + cities: ["太原市", "大同市", "阳泉市", "长治市", "晋城市", "朔州市", "晋中市", "运城市", "忻州市", "临汾市", "吕梁市"], + }, + { + province: "内蒙古自治区", + cities: ["呼和浩特市", "包头市", "乌海市", "赤峰市", "通辽市", "鄂尔多斯市", "呼伦贝尔市", "巴彦淖尔市", "乌兰察布市", "兴安盟", "锡林郭勒盟", "阿拉善盟"], + }, + { + province: "辽宁省", + cities: ["沈阳市", "大连市", "鞍山市", "抚顺市", "本溪市", "丹东市", "锦州市", "营口市", "阜新市", "辽阳市", "盘锦市", "铁岭市", "朝阳市", "葫芦岛市"], + }, + { + province: "吉林省", + cities: ["长春市", "吉林市", "四平市", "辽源市", "通化市", "白山市", "松原市", "白城市", "延边朝鲜族自治州"], + }, + { + province: "黑龙江省", + cities: ["哈尔滨市", "齐齐哈尔市", "鸡西市", "鹤岗市", "双鸭山市", "大庆市", "伊春市", "佳木斯市", "七台河市", "牡丹江市", "黑河市", "绥化市", "大兴安岭地区"], + }, + { province: "上海市", cities: ["上海市"] }, + { + province: "江苏省", + cities: ["南京市", "无锡市", "徐州市", "常州市", "苏州市", "南通市", "连云港市", "淮安市", "盐城市", "扬州市", "镇江市", "泰州市", "宿迁市"], + }, + { + province: "浙江省", + cities: ["杭州市", "宁波市", "温州市", "嘉兴市", "湖州市", "绍兴市", "金华市", "衢州市", "舟山市", "台州市", "丽水市"], + }, + { + province: "安徽省", + cities: ["合肥市", "芜湖市", "蚌埠市", "淮南市", "马鞍山市", "淮北市", "铜陵市", "安庆市", "黄山市", "滁州市", "阜阳市", "宿州市", "六安市", "亳州市", "池州市", "宣城市"], + }, + { + province: "福建省", + cities: ["福州市", "厦门市", "莆田市", "三明市", "泉州市", "漳州市", "南平市", "龙岩市", "宁德市"], + }, + { + province: "江西省", + cities: ["南昌市", "景德镇市", "萍乡市", "九江市", "新余市", "鹰潭市", "赣州市", "吉安市", "宜春市", "抚州市", "上饶市"], + }, + { + province: "山东省", + cities: ["济南市", "青岛市", "淄博市", "枣庄市", "东营市", "烟台市", "潍坊市", "济宁市", "泰安市", "威海市", "日照市", "临沂市", "德州市", "聊城市", "滨州市", "菏泽市"], + }, + { + province: "河南省", + cities: ["郑州市", "开封市", "洛阳市", "平顶山市", "安阳市", "鹤壁市", "新乡市", "焦作市", "濮阳市", "许昌市", "漯河市", "三门峡市", "南阳市", "商丘市", "信阳市", "周口市", "驻马店市", "济源市"], + }, + { + province: "湖北省", + cities: ["武汉市", "黄石市", "十堰市", "宜昌市", "襄阳市", "鄂州市", "荆门市", "孝感市", "荆州市", "黄冈市", "咸宁市", "随州市", "恩施土家族苗族自治州", "仙桃市", "潜江市", "天门市", "神农架林区"], + }, + { + province: "湖南省", + cities: ["长沙市", "株洲市", "湘潭市", "衡阳市", "邵阳市", "岳阳市", "常德市", "张家界市", "益阳市", "郴州市", "永州市", "怀化市", "娄底市", "湘西土家族苗族自治州"], + }, + { + province: "广东省", + cities: ["广州市", "韶关市", "深圳市", "珠海市", "汕头市", "佛山市", "江门市", "湛江市", "茂名市", "肇庆市", "惠州市", "梅州市", "汕尾市", "河源市", "阳江市", "清远市", "东莞市", "中山市", "潮州市", "揭阳市", "云浮市"], + }, + { + province: "广西壮族自治区", + cities: ["南宁市", "柳州市", "桂林市", "梧州市", "北海市", "防城港市", "钦州市", "贵港市", "玉林市", "百色市", "贺州市", "河池市", "来宾市", "崇左市"], + }, + { + province: "海南省", + cities: ["海口市", "三亚市", "三沙市", "儋州市", "五指山市", "琼海市", "文昌市", "万宁市", "东方市", "定安县", "屯昌县", "澄迈县", "临高县", "白沙黎族自治县", "昌江黎族自治县", "乐东黎族自治县", "陵水黎族自治县", "保亭黎族苗族自治县", "琼中黎族苗族自治县"], + }, + { province: "重庆市", cities: ["重庆市"] }, + { + province: "四川省", + cities: ["成都市", "自贡市", "攀枝花市", "泸州市", "德阳市", "绵阳市", "广元市", "遂宁市", "内江市", "乐山市", "南充市", "眉山市", "宜宾市", "广安市", "达州市", "雅安市", "巴中市", "资阳市", "阿坝藏族羌族自治州", "甘孜藏族自治州", "凉山彝族自治州"], + }, + { + province: "贵州省", + cities: ["贵阳市", "六盘水市", "遵义市", "安顺市", "毕节市", "铜仁市", "黔西南布依族苗族自治州", "黔东南苗族侗族自治州", "黔南布依族苗族自治州"], + }, + { + province: "云南省", + cities: ["昆明市", "曲靖市", "玉溪市", "保山市", "昭通市", "丽江市", "普洱市", "临沧市", "楚雄彝族自治州", "红河哈尼族彝族自治州", "文山壮族苗族自治州", "西双版纳傣族自治州", "大理白族自治州", "德宏傣族景颇族自治州", "怒江傈僳族自治州", "迪庆藏族自治州"], + }, + { + province: "西藏自治区", + cities: ["拉萨市", "日喀则市", "昌都市", "林芝市", "山南市", "那曲市", "阿里地区"], + }, + { + province: "陕西省", + cities: ["西安市", "铜川市", "宝鸡市", "咸阳市", "渭南市", "延安市", "汉中市", "榆林市", "安康市", "商洛市"], + }, + { + province: "甘肃省", + cities: ["兰州市", "嘉峪关市", "金昌市", "白银市", "天水市", "武威市", "张掖市", "平凉市", "酒泉市", "庆阳市", "定西市", "陇南市", "临夏回族自治州", "甘南藏族自治州"], + }, + { + province: "青海省", + cities: ["西宁市", "海东市", "海北藏族自治州", "黄南藏族自治州", "海南藏族自治州", "果洛藏族自治州", "玉树藏族自治州", "海西蒙古族藏族自治州"], + }, + { province: "宁夏回族自治区", cities: ["银川市", "石嘴山市", "吴忠市", "固原市", "中卫市"] }, + { + province: "新疆维吾尔自治区", + cities: ["乌鲁木齐市", "克拉玛依市", "吐鲁番市", "哈密市", "昌吉回族自治州", "博尔塔拉蒙古自治州", "巴音郭楞蒙古自治州", "阿克苏地区", "克孜勒苏柯尔克孜自治州", "喀什地区", "和田地区", "伊犁哈萨克自治州", "塔城地区", "阿勒泰地区", "石河子市", "阿拉尔市", "图木舒克市", "五家渠市", "北屯市", "铁门关市", "双河市", "可克达拉市", "昆玉市", "胡杨河市", "新星市", "白杨市"], + }, + { + province: "台湾省", + cities: ["台北市", "新北市", "桃园市", "台中市", "台南市", "高雄市", "基隆市", "新竹市", "嘉义市", "新竹县", "苗栗县", "彰化县", "南投县", "云林县", "嘉义县", "屏东县", "宜兰县", "花莲县", "台东县", "澎湖县", "金门县", "连江县"], + }, + { province: "香港特别行政区", cities: ["香港岛", "九龙", "新界"] }, + { province: "澳门特别行政区", cities: ["澳门半岛", "氹仔", "路环"] }, +]; diff --git a/src/views/index.vue b/src/views/index.vue index a28e347..c6d0d3d 100644 --- a/src/views/index.vue +++ b/src/views/index.vue @@ -1,19 +1,113 @@ - - - \ No newline at end of file + + + diff --git a/src/views/platformAdmin/school/index.vue b/src/views/platformAdmin/school/index.vue new file mode 100644 index 0000000..aec14fd --- /dev/null +++ b/src/views/platformAdmin/school/index.vue @@ -0,0 +1,208 @@ + + + + + diff --git a/src/views/platformAdmin/schoolAdmin/index.vue b/src/views/platformAdmin/schoolAdmin/index.vue new file mode 100644 index 0000000..3e82c59 --- /dev/null +++ b/src/views/platformAdmin/schoolAdmin/index.vue @@ -0,0 +1,176 @@ + + + diff --git a/src/views/schoolAdmin/admin-theme.scss b/src/views/schoolAdmin/admin-theme.scss new file mode 100644 index 0000000..2f198e0 --- /dev/null +++ b/src/views/schoolAdmin/admin-theme.scss @@ -0,0 +1,212 @@ +.school-admin-workbench { + min-height: calc(100vh - 84px); + padding: 24px; + color: #eef5ff; + background: + radial-gradient(circle at 12% 16%, rgba(0, 170, 255, 0.24), transparent 28%), + radial-gradient(circle at 85% 4%, rgba(43, 110, 255, 0.16), transparent 28%), + linear-gradient(135deg, #07101d 0%, #03060c 100%); +} + +.admin-hero { + position: relative; + overflow: hidden; + margin-bottom: 18px; + padding: 22px 24px; + border: 1px solid rgba(0, 180, 255, 0.32); + border-radius: 24px; + background: rgba(8, 18, 28, 0.72); + box-shadow: 0 18px 44px rgba(0, 0, 0, 0.28), inset 0 1px 0 rgba(255, 255, 255, 0.04); + backdrop-filter: blur(14px); +} + +.admin-hero::after { + content: ""; + position: absolute; + inset: 0; + pointer-events: none; + background: + linear-gradient(90deg, rgba(0, 170, 255, 0.16), transparent 38%), + repeating-linear-gradient(90deg, rgba(125, 211, 252, 0.08) 0 1px, transparent 1px 64px); + opacity: 0.42; +} + +.admin-badge { + position: relative; + z-index: 1; + display: inline-flex; + align-items: center; + gap: 8px; + margin-bottom: 10px; + padding: 5px 14px; + border: 1px solid rgba(0, 170, 255, 0.55); + border-radius: 999px; + color: #b9e2ff; + background: rgba(0, 170, 255, 0.15); + font-size: 12px; + font-weight: 600; +} + +.admin-title { + position: relative; + z-index: 1; + margin: 0; + font-size: 28px; + line-height: 1.2; + font-weight: 800; + letter-spacing: 0; + color: transparent; + background: linear-gradient(135deg, #ffffff, #8bcbff); + -webkit-background-clip: text; + background-clip: text; +} + +.admin-subtitle { + position: relative; + z-index: 1; + margin-top: 8px; + color: #9ab3d0; + font-size: 14px; +} + +.admin-panel { + padding: 18px; + border: 1px solid rgba(0, 180, 255, 0.26); + border-radius: 24px; + background: rgba(8, 18, 28, 0.7); + box-shadow: 0 12px 34px rgba(0, 0, 0, 0.24); + backdrop-filter: blur(12px); +} + +.school-admin-workbench .toolbar { + display: flex; + flex-wrap: wrap; + gap: 10px; + align-items: center; + margin-bottom: 14px; + padding: 12px; + border: 1px solid rgba(45, 143, 207, 0.36); + border-radius: 18px; + background: rgba(0, 35, 55, 0.44); +} + +.school-admin-workbench .filter-input { + width: 220px; +} + +.school-admin-workbench .el-input__wrapper, +.school-admin-workbench .el-select .el-input__wrapper { + background: rgba(3, 24, 36, 0.9); + border: 1px solid rgba(45, 95, 126, 0.9); + box-shadow: none; +} + +.school-admin-workbench .el-input__inner { + color: #eef5ff; +} + +.school-admin-workbench .el-input__inner::placeholder { + color: #5f7d9c; +} + +.school-admin-workbench .el-button { + border-radius: 14px; + font-weight: 600; +} + +.school-admin-workbench .el-button--primary, +.school-admin-workbench .el-button--success { + border-color: rgba(0, 170, 255, 0.55); + background: linear-gradient(95deg, #1175a8, #0a5c86); + box-shadow: 0 0 14px rgba(0, 170, 255, 0.16); +} + +.school-admin-workbench .el-table { + overflow: hidden; + border-radius: 18px; + border-color: rgba(45, 143, 207, 0.32); + background: rgba(3, 24, 36, 0.72); + color: #dceeff; +} + +.school-admin-workbench .el-table th.el-table__cell { + background: rgba(0, 42, 68, 0.92); + color: #b9e2ff; + font-weight: 700; +} + +.school-admin-workbench .el-table tr, +.school-admin-workbench .el-table td.el-table__cell { + background: rgba(3, 24, 36, 0.58); + border-color: rgba(45, 143, 207, 0.18); +} + +.school-admin-workbench .el-table__body tr:hover > td.el-table__cell { + background: rgba(0, 160, 255, 0.14); +} + +.school-admin-workbench .pager { + margin-top: 14px; + justify-content: flex-end; +} + +.school-admin-workbench .el-pagination { + --el-pagination-bg-color: transparent; + --el-pagination-button-bg-color: rgba(3, 24, 36, 0.85); + --el-pagination-hover-color: #00aaff; + color: #cde4ff; +} + +.school-admin-workbench .admin-form { + max-width: none; + padding: 18px; + border: 1px solid rgba(45, 143, 207, 0.32); + border-radius: 22px; + background: rgba(0, 20, 35, 0.62); +} + +.school-admin-workbench .el-form-item__label { + color: #b9e2ff; + font-weight: 600; +} + +.el-dialog { + border-radius: 22px; + background: #07101d; + border: 1px solid rgba(0, 180, 255, 0.28); +} + +.el-dialog__title, +.el-dialog .el-form-item__label { + color: #eef5ff; +} + +.el-dialog .el-dialog__body, +.el-dialog .el-dialog__footer { + background: transparent; +} + +.platform-admin-dialog { + display: flex; + max-width: calc(100vw - 32px); + max-height: calc(100vh - 48px); + flex-direction: column; +} + +.platform-admin-dialog .el-dialog__body { + overflow-y: auto; +} + +@media (max-width: 900px) { + .school-admin-workbench { + padding: 14px; + } + + .admin-title { + font-size: 23px; + } + + .school-admin-workbench .filter-input { + width: 100%; + } +} diff --git a/src/views/schoolAdmin/class/index.vue b/src/views/schoolAdmin/class/index.vue new file mode 100644 index 0000000..efe33b0 --- /dev/null +++ b/src/views/schoolAdmin/class/index.vue @@ -0,0 +1,122 @@ + + + diff --git a/src/views/schoolAdmin/faculty/index.vue b/src/views/schoolAdmin/faculty/index.vue new file mode 100644 index 0000000..4815281 --- /dev/null +++ b/src/views/schoolAdmin/faculty/index.vue @@ -0,0 +1,109 @@ + + + diff --git a/src/views/schoolAdmin/major/index.vue b/src/views/schoolAdmin/major/index.vue new file mode 100644 index 0000000..a26d572 --- /dev/null +++ b/src/views/schoolAdmin/major/index.vue @@ -0,0 +1,123 @@ + + + diff --git a/src/views/schoolAdmin/school/index.vue b/src/views/schoolAdmin/school/index.vue new file mode 100644 index 0000000..975f580 --- /dev/null +++ b/src/views/schoolAdmin/school/index.vue @@ -0,0 +1,85 @@ + + + diff --git a/src/views/schoolAdmin/student/index.vue b/src/views/schoolAdmin/student/index.vue new file mode 100644 index 0000000..735ba95 --- /dev/null +++ b/src/views/schoolAdmin/student/index.vue @@ -0,0 +1,124 @@ + + + diff --git a/src/views/schoolAdmin/teacher/index.vue b/src/views/schoolAdmin/teacher/index.vue new file mode 100644 index 0000000..84e1450 --- /dev/null +++ b/src/views/schoolAdmin/teacher/index.vue @@ -0,0 +1,104 @@ + + +