Prechádzať zdrojové kódy

校友相册管理,权限管理,操作日志,系统设置(接口已接完)

hzj18279462576@163.com 4 mesiacov pred
commit
763e2d943e
100 zmenil súbory, kde vykonal 11752 pridanie a 0 odobranie
  1. 2 0
      .env.development
  2. 24 0
      .gitignore
  3. 3 0
      .vscode/extensions.json
  4. 36 0
      README.en.md
  5. 5 0
      README.md
  6. 14 0
      index.html
  7. 6610 0
      package-lock.json
  8. 35 0
      package.json
  9. 1 0
      public/vite.svg
  10. 266 0
      src/App.vue
  11. 60 0
      src/api/account.js
  12. 100 0
      src/api/alumni-album.js
  13. 10 0
      src/api/login.js
  14. 19 0
      src/api/operation-log.js
  15. 44 0
      src/api/permission.js
  16. 72 0
      src/api/role.js
  17. 18 0
      src/api/system.js
  18. 11 0
      src/api/uploadFile.js
  19. 6 0
      src/assets/icons/czrz.svg
  20. 9 0
      src/assets/icons/dzxykgl.svg
  21. 6 0
      src/assets/icons/fxfwgl.svg
  22. 11 0
      src/assets/icons/gcxxgl.svg
  23. 9 0
      src/assets/icons/qxgl.svg
  24. 9 0
      src/assets/icons/xtsz.svg
  25. 9 0
      src/assets/icons/xwjjgl.svg
  26. 9 0
      src/assets/icons/xyfcgl.svg
  27. 9 0
      src/assets/icons/xyhdgl.svg
  28. 6 0
      src/assets/icons/xyhzgl.svg
  29. 6 0
      src/assets/icons/xyqygl.svg
  30. 12 0
      src/assets/icons/xyxcgl.svg
  31. 6 0
      src/assets/icons/xyxxgl.svg
  32. 6 0
      src/assets/icons/xyzzgl.svg
  33. BIN
      src/assets/img/404.png
  34. BIN
      src/assets/img/add.png
  35. BIN
      src/assets/img/add_1.png
  36. BIN
      src/assets/img/bg.png
  37. BIN
      src/assets/img/jiaofei.png
  38. BIN
      src/assets/img/login3.png
  39. BIN
      src/assets/img/login_bg.png
  40. BIN
      src/assets/img/login_logo.png
  41. BIN
      src/assets/img/login_pass.png
  42. BIN
      src/assets/img/login_txt.png
  43. BIN
      src/assets/img/login_user.png
  44. BIN
      src/assets/img/logo.png
  45. BIN
      src/assets/img/luqu.png
  46. BIN
      src/assets/img/nanchang.png
  47. BIN
      src/assets/img/pass.png
  48. BIN
      src/assets/img/phone.png
  49. BIN
      src/assets/img/quit.png
  50. BIN
      src/assets/img/ruzhu.png
  51. BIN
      src/assets/img/upvote.png
  52. BIN
      src/assets/img/upvote_red.png
  53. BIN
      src/assets/img/yubaodao.png
  54. BIN
      src/assets/img/yuyue.png
  55. 6 0
      src/assets/svgs/add.svg
  56. 8 0
      src/assets/svgs/building.svg
  57. 8 0
      src/assets/svgs/caller.svg
  58. 6 0
      src/assets/svgs/car.svg
  59. 4 0
      src/assets/svgs/carNum.svg
  60. 6 0
      src/assets/svgs/dataOverview.svg
  61. 4 0
      src/assets/svgs/delete.svg
  62. 4 0
      src/assets/svgs/dorm.svg
  63. 6 0
      src/assets/svgs/dormitory.svg
  64. 4 0
      src/assets/svgs/entourage.svg
  65. 6 0
      src/assets/svgs/family.svg
  66. 6 0
      src/assets/svgs/filling_details.svg
  67. 4 0
      src/assets/svgs/jiaofei.svg
  68. 11 0
      src/assets/svgs/luqu.svg
  69. 18 0
      src/assets/svgs/moneySetting.svg
  70. 9 0
      src/assets/svgs/pay.svg
  71. 6 0
      src/assets/svgs/quarterage.svg
  72. 6 0
      src/assets/svgs/role.svg
  73. 6 0
      src/assets/svgs/ruzhu.svg
  74. 8 0
      src/assets/svgs/student.svg
  75. 18 0
      src/assets/svgs/student1.svg
  76. 6 0
      src/assets/svgs/studentInfo.svg
  77. 6 0
      src/assets/svgs/system.svg
  78. 1 0
      src/assets/svgs/teacher.svg
  79. 11 0
      src/assets/svgs/yubao.svg
  80. 43 0
      src/components/HelloWorld.vue
  81. 41 0
      src/components/SvgIcon.vue
  82. 241 0
      src/components/richtext.vue
  83. 373 0
      src/layout/Navbar.vue
  84. 173 0
      src/layout/SidevarItem.vue
  85. 366 0
      src/layout/SidevarItem1.vue
  86. 150 0
      src/layout/SidevarItem报修.vue
  87. 60 0
      src/main.js
  88. 146 0
      src/router/index.js
  89. 80 0
      src/stores/index.js
  90. 79 0
      src/style.css
  91. 1 0
      src/styles/mixin.scss
  92. 82 0
      src/utils/request.js
  93. 20 0
      src/utils/rsa.js
  94. 160 0
      src/views/404/404.vue
  95. 621 0
      src/views/alumni-activity/ActivityAudit.vue
  96. 700 0
      src/views/alumni-activity/ActivityList.vue
  97. 93 0
      src/views/alumni-activity/alumni-activity.vue
  98. 0 0
      src/views/alumni-activity/校友活动管理
  99. 702 0
      src/views/alumni-album/PhotoAudit.vue
  100. 0 0
      src/views/alumni-album/PhotoCategory.vue

+ 2 - 0
.env.development

@@ -0,0 +1,2 @@
+# 开发环境配置
+VITE_API_BASE_URL = 'http://localhost:8080'

+ 24 - 0
.gitignore

@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?

+ 3 - 0
.vscode/extensions.json

@@ -0,0 +1,3 @@
+{
+  "recommendations": ["Vue.volar"]
+}

+ 36 - 0
README.en.md

@@ -0,0 +1,36 @@
+# VUE3+vite+JS+pinia
+
+#### Description
+{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
+
+#### Software Architecture
+Software architecture description
+
+#### Installation
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### Instructions
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### Contribution
+
+1.  Fork the repository
+2.  Create Feat_xxx branch
+3.  Commit your code
+4.  Create Pull Request
+
+
+#### Gitee Feature
+
+1.  You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
+2.  Gitee blog [blog.gitee.com](https://blog.gitee.com)
+3.  Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
+4.  The most valuable open source project [GVP](https://gitee.com/gvp)
+5.  The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
+6.  The most popular members  [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

+ 5 - 0
README.md

@@ -0,0 +1,5 @@
+# Vue 3 + Vite
+
+This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
+
+Learn more about IDE Support for Vue in the [Vue Docs Scaling up Guide](https://vuejs.org/guide/scaling-up/tooling.html#ide-support).

+ 14 - 0
index.html

@@ -0,0 +1,14 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
+    <link rel="icon" type="image/png" href="/src/assets/img/nanchang.png" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>校友信息管理系统</title>
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.js"></script>
+  </body>
+</html>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6610 - 0
package-lock.json


+ 35 - 0
package.json

@@ -0,0 +1,35 @@
+{
+  "name": "pack",
+  "private": true,
+  "version": "0.0.0",
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "vite build",
+    "preview": "vite preview"
+  },
+  "dependencies": {
+    "@popperjs/core": "^2.11.8",
+    "@wangeditor/editor": "^5.1.23",
+    "@wangeditor/editor-for-vue": "^5.1.12",
+    "axios": "^1.8.4",
+    "echarts": "^5.6.0",
+    "element-plus": "^2.9.7",
+    "jsencrypt": "^3.3.2",
+    "nprogress": "^0.2.0",
+    "pinia": "^3.0.2",
+    "v-viewer": "^3.0.11",
+    "vue": "^3.5.13",
+    "vue-router": "^4.5.0"
+  },
+  "devDependencies": {
+    "@vitejs/plugin-vue": "^5.2.2",
+    "fast-glob": "^3.3.3",
+    "sass": "^1.86.3",
+    "sass-loader": "^16.0.5",
+    "unplugin-auto-import": "^21.0.0",
+    "unplugin-vue-components": "^31.0.0",
+    "vite": "^6.3.1",
+    "vite-plugin-svg-icons": "^2.0.1"
+  }
+}

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 0
public/vite.svg


+ 266 - 0
src/App.vue

@@ -0,0 +1,266 @@
+<template>
+  <div class="body-box" v-if="isShowHeader">
+    <SidevarItem></SidevarItem>
+    <div class="content">
+      <Navbar></Navbar>
+      <!-- <router-view></router-view> -->
+
+      <router-view v-slot="{ Component, route }">
+        <transition name="animation" mode="out-in">
+          <component :is="Component" :key="route.path" />
+        </transition>
+      </router-view>
+    </div>
+  </div>
+  <div class="body-box" v-else>
+    <router-view></router-view>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onBeforeMount, onMounted, watch } from "vue";
+import Navbar from "@/layout/Navbar.vue";
+import SidevarItem from "@/layout/SidevarItem.vue";
+import { useRouter } from "vue-router";
+
+import { storeToRefs } from "pinia";
+import { useCounterStore } from "@/stores/index";
+const store = useCounterStore();
+
+const router = useRouter();
+const isShowHeader = ref(true);
+
+// 监听路由判断是否显示导航条
+watch(
+  () => router.currentRoute.value,
+  (newValue) => {
+    // console.log(newValue);
+    store.SETMENU(newValue.fullPath);
+    isShowHeader.value = newValue.meta.showHeader;
+  },
+  { immediate: true, deep: true },
+);
+
+const tableData = reactive({
+  list: [],
+});
+onBeforeMount(async () => {
+  // console.log('App/onBeforeMount');
+});
+</script>
+
+<style lang="scss">
+#app {
+  width: 100%;
+  height: 100%;
+  margin: 0;
+  padding: 0;
+  text-align: unset;
+  overflow: auto;
+}
+
+.el-dialog {
+  border-radius: 5px !important;
+  padding: 0 !important;
+  .el-dialog__header {
+    border-radius: 5px 5px 0 0;
+    background: rgba(237, 241, 245, 1);
+    font-weight: 600;
+    height: 56px;
+    margin: 0;
+    padding: 0 0 0 20px;
+    display: flex;
+    align-items: center;
+    .el-dialog__headerbtn {
+      outline: none;
+      top: 4px;
+    }
+  }
+  .el-dialog__body {
+    padding: 20px 20px 0 20px;
+    .el-input {
+      width: 400px;
+    }
+    .el-textarea {
+      width: 400px;
+    }
+    .el-select {
+      width: 400px;
+    }
+    .options {
+      display: flex;
+      flex-direction: row-reverse;
+      .el-form-item__content {
+        margin-left: 0 !important;
+        flex: none;
+      }
+    }
+  }
+}
+
+.is-message-box {
+  .el-message-box__header {
+    .el-message-box__headerbtn {
+      outline: none;
+    }
+  }
+
+  .el-message-box__btns {
+    .el-button {
+      outline: none;
+    }
+    .el-button--primary {
+      background-color: rgba(61, 81, 232, 1);
+      border: 0.5px solid rgba(61, 81, 232, 1);
+    }
+
+    .el-button--primary:hover {
+      background-color: rgb(119, 133, 239);
+      border: 0.5px solid rgb(119, 133, 239);
+    }
+  }
+}
+
+*::-webkit-scrollbar-track {
+  background-color: #fff;
+}
+
+*::-webkit-scrollbar {
+  background-color: #57b2ff;
+  height: 0;
+  width: 0;
+}
+
+*::-webkit-scrollbar-thumb {
+  background: #57b2ff;
+  border-radius: 4px;
+  height: 0;
+  width: 0;
+}
+
+// 进度条颜色
+#nprogress .bar {
+  background-color: rgb(111, 182, 184) !important;
+}
+
+/* 自定义图片预览列表样式 */
+.img-preview-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 12px;
+  :deep(.el-upload-list) {
+    display: none;
+  }
+  // 上传图片样式
+  .img-item {
+    position: relative;
+    width: 140px;
+    height: 140px;
+    border-radius: 4px;
+    overflow: hidden;
+    border: 1px solid #eee;
+    .preview-img {
+      width: 100%;
+      height: 100%;
+      object-fit: contain;
+      cursor: zoom-in;
+    }
+    /* 删除按钮样式 */
+    .delete-btn {
+      position: absolute;
+      top: 0;
+      right: 0;
+      background: rgba(0, 0, 0, 0.5);
+      color: #fff;
+      width: 24px;
+      height: 24px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      cursor: pointer;
+      opacity: 0;
+      transition: opacity 0.3s;
+    }
+    &:hover .delete-btn {
+      opacity: 1;
+    }
+  }
+  .upload-btn {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    // padding: 8px 16px;
+    border: 1px dashed #d9d9d9;
+    border-radius: 4px;
+    cursor: pointer;
+    color: #666;
+    transition: all 0.3s;
+    width: 140px;
+    height: 140px;
+    &:hover {
+      border-color: #409eff;
+      color: #409eff;
+    }
+    .upload-txt {
+      font-size: 14px;
+    }
+    .el-upload {
+      width: 140px;
+      height: 140px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+    }
+    .el-upload-list {
+      display: none;
+    }
+  }
+}
+
+.viewer-container,      /* v-viewer 根容器 */
+.el-image-viewer__wrapper, /* Element 预览层 */
+.photo-preview-modal    /* vue-photo-preview 根容器 */
+{
+  z-index: 9999 !important; /* 远高于所有弹窗/表格 */
+  position: fixed !important; /* 脱离文档流,不继承父层级 */
+  top: 0 !important;
+  left: 0 !important;
+  right: 0 !important;
+  bottom: 0 !important;
+}
+</style>
+<style scoped lang="scss">
+.body-box {
+  display: flex;
+  width: 100%;
+
+  .content {
+    min-width: calc(100% - 200px);
+    max-width: calc(100% - 63px);
+    width: 100%;
+    height: 100vh;
+    background-color: rgba(238, 238, 238, 1);
+
+    :deep(.el-dialog__header .el-dialog__headerbtn) {
+      outline: none;
+    }
+  }
+}
+
+/* 过度动画配置代码 */
+.animation-enter-from,
+.animation-leave-to {
+  transform: translateX(20px);
+  opacity: 0;
+}
+.animation-enter-to,
+.animation-leave-from {
+  opacity: 1;
+}
+.animation-enter-active {
+  transition: all 0.7s ease;
+}
+.animation-leave-active {
+  transition: all 0.3s cubic-bezier(1, 0.6, 0.6, 1);
+}
+</style>

+ 60 - 0
src/api/account.js

@@ -0,0 +1,60 @@
+import request from '@/utils/request' // 你的axios封装文件
+
+// 获取用户列表
+export function getQueryAccountPage(params) {
+  return request({
+    url: '/api/alumniUser/queryAccountPage',
+    method: 'get',
+    params
+  })
+}
+
+// 9.1.	获取审核状态下拉列表数据
+export function getAllStatus() {
+  return request({
+    url: `/api/alumniUser/queryStates`,
+    method: 'get',
+  })
+}
+
+// 9.2.	获取角色下拉列表数据
+export function getAllRole() {
+  return request({
+    url: '/api/alumniUser/queryRoleTypes',
+    method: 'get'
+  })
+}
+
+// 9.3.	根据微校卡号获取用户信息
+export function getUserInfo(params) {
+  return request({
+    url: `/api/alumniUser/queryMobileInfo`,
+    method: 'get',
+    params
+  })
+}
+
+// 9.4.	新增账号
+export function addAccount(data) {
+  return request({
+    url: `/api/alumniUser/insertAccountData`,
+    method: 'post',
+    data: data
+  })
+}
+// 9.5.	删除账号
+export function deleteAccount(params) {
+  return request({
+    url: `/api/alumniUser/deleteUserById`,
+    method: 'get',
+    params
+  })
+}
+// 9.6.	编辑账号
+export function editAccount(data) {
+  return request({
+    url: `/api/alumniUser/updateAccountData`,
+    method: 'post',
+    data: data
+  })
+}

+ 100 - 0
src/api/alumni-album.js

@@ -0,0 +1,100 @@
+import request from "@/utils/request"; // 你的axios封装
+
+// 【【【【【校友相册列表】】】】】
+// 校友相册分页数据
+export function getQueryImagePage(params) {
+  return request({
+    url: "/api/alumniImage/queryImagePage",
+    method: "get",
+    params: params,
+  });
+}
+
+// 获取相册分类下拉列表数据
+export function queryCategoryImages() {
+  return request({
+    url: "/api/alumniCategoryImage/queryCategoryImages",
+    method: "get",
+  });
+}
+
+// 新增校友相册
+export function insertWebImage(data) {
+  return request({
+    url: "/api/alumniImage/insertWebImage",
+    method: "post",
+    data: data,
+  });
+}
+// 编辑校友相册
+export function updateImage(data) {
+  return request({
+    url: "/api/alumniImage/updateImage",
+    method: "post",
+    data: data,
+  });
+}
+
+// 删除校友相册数据
+export function deleteImageById(params) {
+  return request({
+    url: `/api/alumniImage/deleteImageById`,
+    method: "get",
+    params: params,
+  });
+}
+
+// 【【【【【校友相册列表】】】】】】
+// 获取相册分类分页数据
+export function getQueryCategoryImagePage(params) {
+  return request({
+    url: "/api/alumniCategoryImage/queryCategoryImagePage",
+    method: "get",
+    params: params,
+  });
+}
+
+// 新增相册分类数据
+export function insertCategoryImage(data) {
+  return request({
+    url: "/api/alumniCategoryImage/insertCategoryImage",
+    method: "post",
+    data: data,
+  });
+}
+// 更新相册分类数据
+export function updateCategoryImage(data) {
+  return request({
+    url: "/api/alumniCategoryImage/updateCategoryImage",
+    method: "post",
+    data: data,
+  });
+}
+
+// 删除相册分类数据
+export function deleteCategoryImage(params) {
+  return request({
+    url: `/api/alumniCategoryImage/deleteCategoryImage`,
+    method: "get",
+    params: params,
+  });
+}
+
+// 【【【【【照片上传审核】】】】】】
+// 获取校友相册审核分页数据
+export function getQueryImageApplyPage(params) {
+  return request({
+    url: "/api/alumniImage/queryImageApplyPage",
+    method: "get",
+    params: params,
+  });
+}
+
+// 10.11.	审核校友相册数据
+export function toExamineImage(params) {
+  return request({
+    url: "/api/alumniImage/toExamineImage",
+    method: "get",
+    params: params,
+  });
+}

+ 10 - 0
src/api/login.js

@@ -0,0 +1,10 @@
+import request from '@/utils/request' // 你的axios封装文件
+
+// 获取用户列表
+export function login(data) {
+  return request({
+    url: '/api/login/Login',
+    method: 'post',
+    data: data
+  })
+}

+ 19 - 0
src/api/operation-log.js

@@ -0,0 +1,19 @@
+import request from "@/utils/request"; // 你的axios封装
+
+// 14.1.	获取操作日志分页数据
+export function getQueryLogPages(params) {
+  return request({
+    url: "/api/alumniLog/queryLogPages",
+    method: "get",
+    params: params,
+  });
+}
+
+// 14.2.	获取日志级别下拉列表数据
+export function getQueryLogLevel(params) {
+  return request({
+    url: "/api/alumniLog/queryLogLevel",
+    method: "get",
+    params: params,
+  });
+}

+ 44 - 0
src/api/permission.js

@@ -0,0 +1,44 @@
+// 引入axios请求实例(已封装好baseURL、请求拦截器携带token)
+import request from '@/utils/request'
+
+// 1. 查询所有菜单树形结构(仅管理员用)
+export function getAllMenuTree() {
+  return request({
+    url: '/api/menu/list',
+    method: 'get'
+  })
+}
+
+// 2. 查询当前登录用户的可访问菜单(动态路由用)
+export function getUserMenu() {
+  return request({
+    url: '/api/menu/user-menu',
+    method: 'get'
+  })
+}
+
+// 3. 新增菜单
+export function addMenu(data) {
+  return request({
+    url: '/api/menu/add',
+    method: 'post',
+    data // 传菜单对象:{permCode, permName, parentId...}
+  })
+}
+
+// 4. 修改菜单
+export function updateMenu(data) {
+  return request({
+    url: '/api/menu/update',
+    method: 'put',
+    data // 传修改后的菜单对象,必须带id
+  })
+}
+
+// 5. 删除菜单
+export function deleteMenu(id) {
+  return request({
+    url: `/api/menu/delete/${id}`,
+    method: 'delete'
+  })
+}

+ 72 - 0
src/api/role.js

@@ -0,0 +1,72 @@
+import request from "@/utils/request"; // 你的axios封装
+
+// 1. 获取角色列表
+export function getQueryRolesPage(params) {
+  return request({
+    url: "/api/alumniRole/queryRolesPage",
+    method: "get",
+    params: params,
+  });
+}
+
+// 2. 新增角色
+export function addRole(data) {
+  return request({
+    url: "/api/alumniRole/insertRole",
+    method: "post",
+    data: data,
+  });
+}
+
+// 3. 编辑角色
+export function updateRole(data) {
+  return request({
+    url: "/api/alumniRole/updateRole",
+    method: "post",
+    data: data,
+  });
+}
+
+// 4. 删除角色
+export function deleteRole(params) {
+  return request({
+    url: `/api/alumniRole/deleteRoleById`,
+    method: "get",
+    params: params,
+  });
+}
+
+// 16.1.	获取菜单树形图数据
+export function getAllMenus() {
+  return request({
+    url: `/api/alumniMenu/queryAllMenus`,
+    method: "get",
+  });
+}
+
+// 查询角色
+export function getByIdMenu(params) {
+  return request({
+    url: `/api/alumniRole/queryRole`,
+    method: "get",
+    params
+  });
+}
+
+// 16.2.	获取省下拉列表
+export function getProvince(params) {
+  return request({
+    url: `/api/alumniCity/getProvinceLevel`,
+    method: "get",
+    params: params,
+  });
+}
+
+// 16.3.	获取市下拉列表
+export function getCity(params) {
+  return request({
+    url: `/api/alumniCity/getCityLevel`,
+    method: "get",
+    params: params,
+  });
+}

+ 18 - 0
src/api/system.js

@@ -0,0 +1,18 @@
+import request from '@/utils/request' // 你的axios封装文件
+
+// 查询系统设置
+export function getQueryAlumniSystem(params) {
+  return request({
+    url: `/api/alumniSystem/queryAlumniSystem`,
+    method: 'get',
+    params
+  })
+}
+// 修改系统设置
+export function updateAlumniSystem(data) {
+  return request({
+    url: `/api/alumniSystem/updateAlumniSystem`,
+    method: 'post',
+    data: data
+  })
+}

+ 11 - 0
src/api/uploadFile.js

@@ -0,0 +1,11 @@
+import request from '@/utils/request' // 你的axios封装文件
+
+// 图片上传
+export function uploadFile(data) {
+  return request({
+    url: '/api/file/uploadFile',
+    method: 'post',
+    data: data,
+    headers: { 'Content-Type': 'multipart/form-data' }
+  })
+}

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/icons/czrz.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 9 - 0
src/assets/icons/dzxykgl.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/icons/fxfwgl.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 11 - 0
src/assets/icons/gcxxgl.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 9 - 0
src/assets/icons/qxgl.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 9 - 0
src/assets/icons/xtsz.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 9 - 0
src/assets/icons/xwjjgl.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 9 - 0
src/assets/icons/xyfcgl.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 9 - 0
src/assets/icons/xyhdgl.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/icons/xyhzgl.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/icons/xyqygl.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 12 - 0
src/assets/icons/xyxcgl.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/icons/xyxxgl.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/icons/xyzzgl.svg


BIN
src/assets/img/404.png


BIN
src/assets/img/add.png


BIN
src/assets/img/add_1.png


BIN
src/assets/img/bg.png


BIN
src/assets/img/jiaofei.png


BIN
src/assets/img/login3.png


BIN
src/assets/img/login_bg.png


BIN
src/assets/img/login_logo.png


BIN
src/assets/img/login_pass.png


BIN
src/assets/img/login_txt.png


BIN
src/assets/img/login_user.png


BIN
src/assets/img/logo.png


BIN
src/assets/img/luqu.png


BIN
src/assets/img/nanchang.png


BIN
src/assets/img/pass.png


BIN
src/assets/img/phone.png


BIN
src/assets/img/quit.png


BIN
src/assets/img/ruzhu.png


BIN
src/assets/img/upvote.png


BIN
src/assets/img/upvote_red.png


BIN
src/assets/img/yubaodao.png


BIN
src/assets/img/yuyue.png


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/svgs/add.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 8 - 0
src/assets/svgs/building.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 8 - 0
src/assets/svgs/caller.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/svgs/car.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 4 - 0
src/assets/svgs/carNum.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/svgs/dataOverview.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 4 - 0
src/assets/svgs/delete.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 4 - 0
src/assets/svgs/dorm.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/svgs/dormitory.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 4 - 0
src/assets/svgs/entourage.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/svgs/family.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/svgs/filling_details.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 4 - 0
src/assets/svgs/jiaofei.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 11 - 0
src/assets/svgs/luqu.svg


+ 18 - 0
src/assets/svgs/moneySetting.svg

@@ -0,0 +1,18 @@
+<svg t="1752225173120" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3564"
+    width="200" height="200">
+    <path
+        d="M990.72 321.28H33.28c-12.8 0-24.32-8.96-29.44-21.76-2.56-12.8 3.84-26.88 15.36-33.28l481.28-230.4c8.96-3.84 17.92-3.84 24.32 0l476.16 229.12c11.52 6.4 17.92 20.48 15.36 33.28-1.28 14.08-12.8 23.04-25.6 23.04z m-828.16-57.6h701.44L514.56 93.44 162.56 263.68z"
+        p-id="3565"></path>
+    <path
+        d="M832 290.56h57.6v533.76H832V290.56z m-698.88 21.76H192v500.48h-57.6V312.32z m363.52 216.32l-90.88-90.88c-8.96-8.96-8.96-24.32 0-35.84 8.96-8.96 24.32-8.96 35.84 0l90.88 90.88c8.96 8.96 8.96 24.32 0 35.84-8.96 8.96-24.32 8.96-35.84 0z"
+        p-id="3566"></path>
+    <path
+        d="M491.52 528.64c-8.96-8.96-8.96-24.32 0-35.84l90.88-90.88c8.96-8.96 24.32-8.96 35.84 0 8.96 8.96 8.96 24.32 0 35.84l-90.88 90.88c-11.52 8.96-26.88 8.96-35.84 0z"
+        p-id="3567"></path>
+    <path
+        d="M638.72 546.56H385.28c-12.8 0-24.32-11.52-24.32-24.32s11.52-24.32 24.32-24.32h252.16c12.8 0 24.32 11.52 24.32 24.32 1.28 12.8-8.96 24.32-23.04 24.32z m0 102.4H385.28c-12.8 0-24.32-11.52-24.32-24.32s11.52-24.32 24.32-24.32h252.16c12.8 0 24.32 11.52 24.32 24.32 1.28 12.8-8.96 24.32-23.04 24.32z"
+        p-id="3568"></path>
+    <path
+        d="M512 742.4c-12.8 0-24.32-11.52-24.32-24.32V546.56c0-12.8 11.52-24.32 24.32-24.32 12.8 0 24.32 11.52 24.32 24.32V716.8c0 14.08-11.52 25.6-24.32 25.6zM928 872.96h-832c-15.36 0-29.44-12.8-29.44-29.44s12.8-29.44 29.44-29.44h832c15.36 0 29.44 12.8 29.44 29.44s-14.08 29.44-29.44 29.44zM994.56 990.72H29.44c-15.36 0-29.44-12.8-29.44-29.44s12.8-29.44 29.44-29.44h966.4c15.36 0 29.44 12.8 29.44 29.44s-14.08 29.44-30.72 29.44z"
+        p-id="3569"></path>
+</svg>

+ 9 - 0
src/assets/svgs/pay.svg

@@ -0,0 +1,9 @@
+<svg t="1750908578163" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1717"
+    width="256" height="256">
+    <path
+        d="M643.328 568.32h-93.5424v-52.6848h93.5424a30.72 30.72 0 0 0 0-61.44h-56.32l62.6176-71.3728a30.72 30.72 0 1 0-46.08-40.5504l-84.48 96.0512-84.2752-96.0512a30.72 30.72 0 0 0-46.08 40.5504l62.5152 71.3728h-56.32a30.72 30.72 0 0 0 0 61.44h93.44V568.32H394.8032a30.72 30.72 0 0 0 0 61.44h93.5424v54.784a30.72 30.72 0 0 0 61.44 0V629.76h93.5424a30.72 30.72 0 0 0 0-61.44z"
+         p-id="1718"></path>
+    <path
+        d="M861.5936 927.8976h-352.768a414.3104 414.3104 0 1 1 379.904-248.4224 30.72 30.72 0 1 1-56.32-24.6272 353.28 353.28 0 1 0-323.6352 211.6096h278.6816l-83.5584-83.5584a30.72 30.72 0 0 1 43.4176-43.4176L883.3536 875.52a30.72 30.72 0 0 1-21.76 52.4288z"
+         p-id="1719"></path>
+</svg>

+ 6 - 0
src/assets/svgs/quarterage.svg

@@ -0,0 +1,6 @@
+<svg t="1750921052345" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
+    p-id="15949" width="200" height="200">
+    <path
+        d="M929 959H95a30 30 0 1 1 0-60h26V115a50 50 0 0 1 50-50h460a50 50 0 0 1 50 50v784h162V462a20 20 0 0 0-20-20h-43a30 30 0 0 1 0-60h73a50 50 0 0 1 50 50v467h26a30 30 0 0 1 0 60zM621 145a20 20 0 0 0-20-20H201a20 20 0 0 0-20 20v754h440V145z m-313 87h186a30 30 0 0 1 0 60H308a30 30 0 0 1 0-60z m0 150h186a30 30 0 0 1 0 60H308a30 30 0 0 1 0-60z m0 150h186a30 30 0 0 1 0 60H308a30 30 0 0 1 0-60z m0 150h186a30 30 0 0 1 0 60H308a30 30 0 0 1 0-60z"
+        fill="#000000" p-id="15950"></path>
+</svg>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/svgs/role.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/svgs/ruzhu.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 8 - 0
src/assets/svgs/student.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 18 - 0
src/assets/svgs/student1.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/svgs/studentInfo.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 6 - 0
src/assets/svgs/system.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 0
src/assets/svgs/teacher.svg


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 11 - 0
src/assets/svgs/yubao.svg


+ 43 - 0
src/components/HelloWorld.vue

@@ -0,0 +1,43 @@
+<script setup>
+import { ref } from 'vue'
+
+defineProps({
+  msg: String,
+})
+
+const count = ref(0)
+</script>
+
+<template>
+  <h1>{{ msg }}</h1>
+
+  <div class="card">
+    <button type="button" @click="count++">count is {{ count }}</button>
+    <p>
+      Edit
+      <code>components/HelloWorld.vue</code> to test HMR
+    </p>
+  </div>
+
+  <p>
+    Check out
+    <a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
+      >create-vue</a
+    >, the official Vue + Vite starter
+  </p>
+  <p>
+    Learn more about IDE Support for Vue in the
+    <a
+      href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
+      target="_blank"
+      >Vue Docs Scaling up Guide</a
+    >.
+  </p>
+  <p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
+</template>
+
+<style scoped>
+.read-the-docs {
+  color: #888;
+}
+</style>

+ 41 - 0
src/components/SvgIcon.vue

@@ -0,0 +1,41 @@
+<script setup>
+import { computed } from "vue";
+
+let props = defineProps({
+  name: {
+    type: String,
+    required: false,
+  },
+  prefix: {
+    type: String,
+    default: "icon",
+  },
+  color: {
+    type: String,
+    default: "#000",
+  },
+  size: {
+    type: String,
+    default: "22",
+  },
+});
+
+const symbolId = computed(() => `#${props.prefix}-${props.name}`);
+</script>
+
+<template>
+  <svg
+    aria-hidden="true"
+    class="el-icon"
+    :style="{ 'width': size + 'px', 'height': size + 'px', 'fill': color }"
+  >
+    <use :xlink:href="symbolId" :fill="color" />
+  </svg>
+</template>
+
+<style lang="scss" scoped>
+.svg-icon {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 241 - 0
src/components/richtext.vue

@@ -0,0 +1,241 @@
+<template>
+  <div class="richText">
+    <div class="box" style="">
+      <Toolbar
+        class="boxToolbar"
+        :editor="editorRef"
+        :defaultConfig="toolbarConfig"
+        :mode="mode"
+      />
+      <Editor
+        class="boxEditor"
+        v-model="valueHtml"
+        :defaultConfig="editorConfig"
+        :mode="mode"
+        @onCreated="handleCreated"
+        @onChange="handleChange"
+        @onDestroyed="handleDestroyed"
+        @onFocus="handleFocus"
+        @onBlur="handleBlur"
+        @customAlert="customAlert"
+        @customPaste="customPaste"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { useRouter } from "vue-router";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { Calendar } from "@element-plus/icons-vue";
+import { dayjs } from "element-plus";
+import lodash, { reduce } from "lodash";
+import { https } from "@/utils/request"; // 绝对路径
+
+import "@wangeditor/editor/dist/css/style.css"; // 引入 css
+
+import { onBeforeUnmount, nextTick, ref, shallowRef, onMounted } from "vue";
+import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
+import { DomEditor, createToolbar } from "@wangeditor/editor";
+
+// 编辑器实例,必须用 shallowRef
+const editorRef = shallowRef();
+
+const props = defineProps({
+  fatherMessage: {},
+});
+const emit = defineEmits(["richtextClick"]);
+
+// 内容 HTML
+const valueHtml = ref();
+const toolbarConfig = {
+  // JS 语法
+  /* 工具栏配置 */
+  excludeKeys: [
+    "insertLink",
+    "insertVideo",
+    "insertTable",
+    "fullScreen",
+    "insertImage",
+    // "group-image",
+    "group-video",
+    "todo",
+  ],
+};
+const uploadImg = async (file, insertFn) => {
+  // let imgData = new FormData();
+  console.log(file);
+  let srcImg = file;
+  let data = new FormData();
+  data.set("file", srcImg);
+  let res = await https.post("/files/upload", "data", data);
+  console.log(res, "导入照片");
+  if (res.code == 200) {
+    let href = res.data;
+    insertFn(href);
+    ElMessage({
+      type: "success",
+      showClose: true,
+      message: res.msg,
+      center: true,
+    });
+  } else {
+    ElMessage({
+      type: "error",
+      showClose: true,
+      message: res.msg,
+      center: true,
+    });
+  }
+};
+const editorConfig = {
+  placeholder: "请输入内容......",
+  MENU_CONF: {
+    uploadImage: {
+      // 自定义上传图片 方法
+      customUpload: uploadImg,
+      // 自定义插入图片 方法
+      // customInsert: insertImg,
+      //上传图片配置
+      // server: "https://	jgy-1325577833.cos.ap-guangzhou.myqcloud.com", //上传接口地址
+      fieldName: "file", //上传文件名
+      methods: "post",
+      metaWithUrl: false, // 参数拼接到 url 上
+      // 单个文件上传成功之后
+      // onSuccess(file, res) {
+      //   console.log(file, res);
+      // },
+      // 自定义插入图片
+      customInsert(res, insertFn) {
+        console.log(res);
+        // insertFn(res.url)
+      },
+    },
+    // insertImage: {
+    //   onInsertedImage(imageNode) {
+    //     if (imageNode == null) return;
+    //     const { src, alt, url, href } = imageNode;
+    //     console.log("inserted image", src, alt, url, href);
+    //   },
+    //   checkImage: customCheckImageFn, // 也支持 async 函数
+    //   parseImageSrc: customParseImageSrc, // 也支持 async 函数
+    // },
+    // editImage: {
+    //   onUpdatedImage(imageNode) {
+    //     if (imageNode == null) return;
+    //     const { src, alt, url } = imageNode;
+    //     console.log("updated image", src, alt, url);
+    //   },
+    //   checkImage: customCheckImageFn, // 也支持 async 函数
+    //   parseImageSrc: customParseImageSrc, // 也支持 async 函数
+    // },
+  },
+};
+const mode = ref("default"); // 默认模式
+// const mode = ref("simple"); // 简易模式
+
+const handleChange = (editor) => {
+  // console.log("change:", editor);
+  // console.log("change:", editor.getText());
+  // console.log("change:", editor.getHtml());
+  emit("richtextClick", {
+    html: editor.getHtml(),
+    text: editor.getText(),
+  });
+};
+const handleDestroyed = (editor) => {
+  console.log("destroyed", editor);
+};
+const handleFocus = (editor) => {
+  console.log("focus", editor);
+  const toolbar = DomEditor.getToolbar(editor);
+
+  const curToolbarConfig = toolbar.getConfig();
+  console.log(curToolbarConfig.toolbarKeys); // 当前菜单排序和分组
+};
+const handleBlur = (editor) => {
+  console.log("blur", editor);
+};
+const customAlert = (info, type) => {
+  alert(`【自定义提示】${type} - ${info}`);
+};
+// 粘贴事件对象
+const customPaste = (editor, event, callback) => {
+  console.log("ClipboardEvent 粘贴事件对象", event);
+  const html = event.clipboardData.getData("text/html"); // 获取粘贴的 html
+  const text = event.clipboardData.getData("text/plain"); // 获取粘贴的纯文本
+  const rtf = event.clipboardData.getData("text/rtf"); // 获取 rtf 数据(如从 word wsp 复制粘贴)
+  console.log(html);
+
+  // 自定义插入内容
+  // editor.insertText("自定义插入内容");
+
+  // 返回 false ,阻止默认粘贴行为
+  // event.preventDefault();
+  // callback(false); // 返回值(注意,vue 事件的返回值,不能用 return)
+
+  // 返回 true ,继续默认的粘贴行为
+  callback(true);
+};
+
+// // 自定义图片上传
+// editorConfig.MENU_CONF["uploadImage"] = {
+//   async customUpload(file, insertFn) {
+//     let formData = new FormData();
+//     formData.append("files", file);
+//     try {
+//       // 这里结合实际场景写自己上传图片的逻辑,此处代码仅为示例
+//       const { data } = await upload(formData);
+//       // 对图片进行处理,同样需要结合实际场景
+//       data.forEach((item) => {
+//         insertFn(item, "image", item);
+//       });
+//     } catch (error) {
+//       console.log(error);
+//     }
+//   },
+// };
+
+const handleCreated = (editor) => {
+  editorRef.value = editor; // 记录 editor 实例,重要!
+  console.log(props.fatherMessage);
+  editor.setHtml(props.fatherMessage.data);
+  // if (props.fatherMessage.flag) {
+  //   editor.enable();
+  // } else {
+  //   editor.disable();
+  // }
+};
+
+// 模拟 ajax 异步获取内容
+onMounted(() => {
+  // console.log(props.fatherMessage.data);
+});
+
+// 组件销毁时,也及时销毁编辑器
+onBeforeUnmount(() => {
+  console.log("销毁组件");
+  const editor = editorRef.value;
+  if (editor == null) return;
+  editor.destroy();
+});
+</script>
+
+<style scoped lang="scss">
+.richText {
+  width: 100%;
+  min-height: 300px;
+  .box {
+    height: 100%;
+    .boxToolbar{
+      border-top: 1px solid #ccc;
+      border-left: 1px solid #ccc;
+      border-right: 1px solid #ccc;
+    }
+    .boxEditor{
+      height: calc(100% - 80px) !important;
+      border: 1px solid #ccc;
+    }
+  }
+}
+</style>

+ 373 - 0
src/layout/Navbar.vue

@@ -0,0 +1,373 @@
+<template>
+  <el-menu
+    :default-active="activeIndex"
+    class="el-menu-demo"
+    mode="horizontal"
+    background-color=""
+    text-color="#000"
+    active-text-color="#4392f7"
+    @select="handleSelect"
+  >
+    <el-icon
+      :size="20"
+      v-show="!isCollapse"
+      class="fold"
+      @click="handleClick"
+      color="#000"
+      ><Fold
+    /></el-icon>
+    <el-icon :size="20" v-show="isCollapse" class="fold" @click="handleClick"
+      ><Expand
+    /></el-icon>
+    <div class="logo">
+      <img src="@/assets/img/nanchang.png" style="width: 30px; height: 30px" />
+      <span>校友信息管理系统</span>
+    </div>
+    <div class="login">
+      <span class="dateTime">{{ dateTime }}</span>
+      <!-- <el-badge :value="titlenumber" class="item">
+        <SvgIcon
+          name="news"
+          class="iconClass"
+          style="cursor: pointer"
+        ></SvgIcon>
+      </el-badge> -->
+      <div class="flex flex-wrap items-center" style="cursor: pointer">
+        <el-dropdown :hide-on-click="false" trigger="click">
+          <img src="@/assets/img/quit.png"  style="width: 25px; height: 25px"/>
+          <!-- <el-avatar :size="30">
+          </el-avatar> -->
+          <template #dropdown>
+            <el-dropdown-menu>
+              <!-- <el-dropdown-item @click="uppassword">
+                <el-icon class="switchButton" :size="20" color="#000">
+                  <img
+                    style="width: 20px; height: 20px"
+                    src="@/assets/img/pass.png"
+                  />
+                </el-icon>
+                <span>修改密码</span>
+              </el-dropdown-item> -->
+
+              <el-dropdown-item @click="loginOut">
+                <el-icon class="switchButton" :size="20" color="#000">
+                  <img
+                    style="width: 20px; height: 20px"
+                    src="@/assets/img/quit.png"
+                  />
+                </el-icon>
+                <span>退出登录</span>
+              </el-dropdown-item>
+            </el-dropdown-menu>
+          </template>
+        </el-dropdown>
+      </div>
+      <span class="name">{{ account }}</span>
+    </div>
+  </el-menu>
+  <el-dialog
+    :append-to-body="true"
+    class="pw"
+    v-model="uppasswordShow"
+    title="修改密码"
+    width="520"
+    :before-close="uppasswordClose"
+    align-center
+    :close-on-click-modal="false"
+  >
+    <el-form
+      ref="ruleFormRef"
+      :model="ruleForm"
+      :rules="rules"
+      label-width="100px"
+      class="demo-ruleForm"
+      :size="formSize"
+      label-position="left"
+      status-icon
+    >
+      <el-form-item label="原密码" prop="oldpass">
+        <el-input
+          v-model="ruleForm.oldpass"
+          placeholder="请输入原密码"
+          clearable
+        />
+      </el-form-item>
+      <el-form-item label="新密码" prop="nowpass">
+        <el-input
+          v-model="ruleForm.nowpass"
+          placeholder="请输入新密码"
+          clearable
+        />
+      </el-form-item>
+      <el-form-item
+        label="确定新密码"
+        prop="correctpass"
+        style="
+          padding-bottom: 40px;
+          border-bottom: 1px solid rgba(230, 230, 230, 1);
+        "
+      >
+        <el-input
+          v-model="ruleForm.correctpass"
+          placeholder="请再次输入新密码"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item class="options">
+        <el-button
+          class="queding"
+          type="primary"
+          @click="submitForm(ruleFormRef)"
+        >
+          确定
+        </el-button>
+        <el-button class="congzhi" @click="resetForm(ruleFormRef)"
+          >重置</el-button
+        >
+      </el-form-item>
+    </el-form>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, reactive, onBeforeMount, onMounted, watch } from "vue";
+import { ElMessage, ElMessageBox, ElNotification } from "element-plus";
+import { useRouter } from "vue-router";
+import { dayjs } from "element-plus";
+import { Fold, Expand, Lock, SwitchButton } from "@element-plus/icons-vue";
+import request from "@/utils/request"; // 绝对路径
+
+import { storeToRefs } from "pinia";
+import { useCounterStore } from "@/stores/index";
+
+const store = useCounterStore();
+const { isCollapse,avatar } = storeToRefs(store);
+const handleClick = () => {
+  store.setInfo(!isCollapse.value);
+};
+const router = useRouter();
+const account = ref(); // 账号名称
+const titlenumber = ref(1); //  消息条数
+const activeIndex = ref(); // 路由路径
+const loginOutDialogVisible = ref(false); // 退出按钮
+const menuclose = ref(false); // 左边状态栏展开按钮状态
+const uppasswordShow = ref(false); // 修改密码展示框
+const ruleForm = reactive({
+  oldpass: "",
+  nowpass: "",
+  correctpass: "",
+});
+const ruleFormRef = ref();
+// 表单验证
+const rules = reactive({
+  oldpass: [
+    {
+      required: true,
+      message: "密码不能为空",
+      trigger: "blur",
+    },
+  ],
+  nowpass: [
+    {
+      required: true,
+      message: "新密码不能为空",
+      trigger: "blur",
+    },
+  ],
+  correctpass: [
+    {
+      required: true,
+      message: "两次密码是否输入正确",
+      trigger: "blur",
+    },
+  ],
+  // desc: [{ required: true, message: "Please input activity form", trigger: "blur" }],
+});
+
+const dateTime = ref(
+  dayjs().format("YYYY-MM-DD") + ` 星期四 ` + dayjs().format("HH:mm:ss")
+); // 时间
+
+// 选择菜单
+const handleSelect = (key, keyPath) => {
+  activeIndex.value = key;
+};
+
+// 修改密码
+const uppassword = () => {
+  uppasswordShow.value = true;
+};
+const uppasswordClose = () => {
+  uppasswordShow.value = false;
+  ruleFormRef.value.resetFields();
+};
+// 提交修改密码表单
+// const submitForm = async (formEl) => {
+//   if (!formEl) return;
+//   await formEl.validate(async (valid, fields) => {
+//     if (valid) {
+//       let data = {
+//         role: localStorage.getItem("role"),
+//         account: localStorage.getItem("account"),
+//         password: ruleForm.oldpass,
+//         newPassword: ruleForm.nowpass,
+//         // confirmPassword: ruleForm.correctpass,
+//       };
+//       if (ruleForm.nowpass == ruleForm.correctpass) {
+//         let resUpdata = await https.post("/updatePassWord", "data", data);
+//         console.log(resUpdata);
+//         if (resUpdata.code == 200) {
+//           ElMessage({
+//             type: "success",
+//             showClose: true,
+//             message: resUpdata.msg,
+//             center: true,
+//           });
+//           sessionStorage.removeItem("token");
+//           sessionStorage.removeItem("userhead");
+//           localStorage.removeItem("pass");
+//           uppasswordShow.value = false;
+//           ruleFormRef.value.resetFields();
+//           ElNotification({
+//             type: "warning",
+//             title: "提示!!!",
+//             message: "密码已修改,请重新登录页面",
+//             // duration: 0,
+//             // position: "top-right",
+//           });
+//         } else {
+//           ElMessage({
+//             type: "error",
+//             showClose: true,
+//             message: resUpdata.msg,
+//             center: true,
+//           });
+//         }
+//       } else {
+//         ElMessage({
+//           type: "error",
+//           showClose: true,
+//           message: "两次密码输入不正确",
+//           center: true,
+//         });
+//       }
+//     } else {
+//       console.log("error submit!", fields);
+//     }
+//   });
+// };
+// 重置表单
+const resetForm = (formEl) => {
+  // console.log("重置表单");
+  if (!formEl) return;
+  formEl.resetFields();
+};
+
+const loginOut = () => {
+  ElMessageBox.confirm("是否退出登录?", "提示", {
+    confirmButtonText: "确认",
+    cancelButtonText: "取消",
+    type: "warning",
+  })
+    .then(() => {
+      sessionStorage.removeItem("token");
+      router.push({
+        path: `/login`,
+      });
+      ElMessage({
+        type: "success",
+        message: "退出成功",
+      });
+    })
+    .catch(() => {
+      ElMessage({
+        type: "info",
+        message: "已取消登录",
+      });
+    });
+};
+
+onMounted(() => {
+  setInterval(() => {
+    var week = ["日", "一", "二", "三", "四", "五", "六"];
+    var datas = dayjs().day();
+    dateTime.value =
+      dayjs().format("YYYY-MM-DD") +
+      ` 星期${week[datas]} ` +
+      dayjs().format("HH:mm:ss");
+  }, 1000);
+});
+onBeforeMount(() => {
+  account.value = sessionStorage.getItem("userName");
+  
+});
+</script>
+
+<style scoped lang="scss">
+.el-menu--horizontal {
+  border-bottom: none;
+  display: flex;
+  align-items: center;
+  height: 65px;
+  // width: 100%;
+  background-color: #fff;
+  box-shadow: 5px 5px 10px 0px rgba(213, 228, 252, 1);
+  .logo {
+    left: 90px;
+    display: flex;
+    align-items: center;
+    span {
+      margin-left: 10px;
+      font-size: 24px;
+      font-weight: 600;
+    }
+  }
+  .login {
+    color: #000;
+    display: flex;
+    align-items: center;
+    position: absolute;
+    right: 10px;
+    top: 17px;
+
+    .dateTime {
+      margin-right: 20px;
+    }
+    .el-badge {
+      display: flex;
+      align-items: center;
+      // :deep(.el-badge__content) {
+      //   width: 2px;
+      //   height: 14px;
+      // }
+    }
+    .items-center {
+      margin-left: 20px;
+    }
+    .name {
+      height: 20px;
+      line-height: 20px;
+      text-decoration: underline;
+      padding: 0 10px;
+      margin: 0 10px;
+      border-left: 2px solid #ccc;
+    }
+    .switchButton {
+      cursor: pointer;
+      background-color: transparent;
+    }
+  }
+  .login:focus {
+    outline: none;
+  }
+  .fold {
+    width: 46px;
+    height: 65px;
+  }
+  .fold:hover {
+    cursor: pointer;
+    background-color: rgba(67, 146, 249, 0.1);
+  }
+}
+</style>

+ 173 - 0
src/layout/SidevarItem.vue

@@ -0,0 +1,173 @@
+<template>
+  <div class="box-item">
+    <el-menu
+      class="el-menu-vertical-demo"
+      background-color="#293749"
+      text-color="#fff"
+      active-text-color="#fff"
+      unique-opened
+      :default-active="menuActive"
+      :collapse="isCollapse"
+      @open="handleOpen"
+      @close="handleClose"
+      @select="handleSelect"
+    >
+      <div class="logo el-menu-item">
+        <el-icon :size="20"
+          ><img src="@/assets/img/nanchang.png" style="width: 40px; height:40px"
+        /></el-icon>
+      </div>
+      <el-menu-item index="/alumni-info">
+        <SvgIcon name="xyxxgl" color="#fff" size="20"></SvgIcon>
+        <template #title>校友信息管理</template>
+      </el-menu-item>
+      <el-menu-item index="/alumni-organization">
+        <SvgIcon name="xyzzgl" color="#fff" size="22"></SvgIcon>
+        <template #title>校友组织管理</template>
+      </el-menu-item>
+      <el-menu-item index="/alumni-activity">
+        <SvgIcon name="xyhdgl" color="#fff" size="20"></SvgIcon>
+        <template #title>校友活动管理</template>
+      </el-menu-item>
+      <el-menu-item index="/alumni-square">
+        <SvgIcon name="gcxxgl" color="#fff" size="22"></SvgIcon>
+        <template #title>广场信息管理</template>
+      </el-menu-item>
+      <el-menu-item index="/alumni-cooperation">
+        <SvgIcon name="xyhzgl" color="#fff" size="22"></SvgIcon>
+        <template #title>校友合作管理</template>
+      </el-menu-item>
+      <el-menu-item index="/alumni-enterprise">
+        <SvgIcon name="xyqygl" color="#fff" size="22"></SvgIcon>
+        <template #title>校友企业管理</template>
+      </el-menu-item>
+      <el-menu-item index="/alumni-style">
+        <SvgIcon name="xyfcgl" color="#fff" size="20"></SvgIcon>
+        <template #title>校友风采管理</template>
+      </el-menu-item>
+      <el-menu-item index="/alumni-new">
+        <SvgIcon name="xwjjgl" color="#fff" size="22"></SvgIcon>
+        <template #title>新闻聚焦管理</template>
+      </el-menu-item>
+      <el-menu-item index="/homecoming-service">
+        <SvgIcon name="fxfwgl" color="#fff" size="24"></SvgIcon>
+        <template #title>返校服务管理</template>
+      </el-menu-item>
+      <el-menu-item index="/alumni-card">
+        <SvgIcon name="dzxykgl" color="#fff" size="20"></SvgIcon>
+        <template #title>电子校友卡管理</template>
+      </el-menu-item>
+      <el-menu-item index="/alumni-album">
+        <SvgIcon name="xyxcgl" color="#fff" size="20"></SvgIcon>
+        <template #title>校友相册管理</template>
+      </el-menu-item>
+      <el-menu-item index="/permission">
+        <SvgIcon name="qxgl" color="#fff" size="20"></SvgIcon>
+        <template #title>权限管理</template>
+      </el-menu-item>
+      <el-menu-item index="/operation-log">
+        <SvgIcon name="czrz" color="#fff" size="22"></SvgIcon>
+        <template #title>操作日志</template>
+      </el-menu-item>
+      <el-menu-item index="/system-setting">
+        <SvgIcon name="xtsz" color="#fff" size="20"></SvgIcon>
+        <template #title>系统设置</template>
+      </el-menu-item>
+      <!-- <el-sub-menu :index="1">
+        <template #title>
+          <SvgIcon name="/user" color="#fff" size="22"></SvgIcon>
+          <span>系统管理</span>
+        </template>
+        <el-menu-item index="/user">
+          <SvgIcon name="user" color="#fff" size="22"></SvgIcon>
+          <template #title>用户管理</template>
+        </el-menu-item>
+        <el-menu-item index="/role">
+          <SvgIcon name="role" color="#fff" size="22"></SvgIcon>
+          <template #title>角色管理</template>
+        </el-menu-item>
+        <el-menu-item index="/permission">
+          <SvgIcon name="permission" color="#fff" size="22"></SvgIcon>
+          <template #title>权限管理</template>
+        </el-menu-item>
+      </el-sub-menu> -->
+    </el-menu>
+  </div>
+</template>
+
+<script setup>
+import { ref, onBeforeMount, onMounted, watch, reactive } from "vue";
+import { useRouter } from "vue-router";
+import { storeToRefs } from "pinia";
+import { useCounterStore } from "@/stores/index";
+
+const store = useCounterStore();
+const { isCollapse, menuActive, roleList } = storeToRefs(store);
+
+const router = useRouter();
+
+const acitveItems = reactive({ list: [] });
+
+const handleSelect = (key) => {
+  console.log(key);
+
+  // store.SETMENU(key);
+  router.push({
+    path: `${key}`,
+  });
+};
+const handleOpen = () => {};
+const handleClose = () => {};
+onBeforeMount(() => {});
+</script>
+
+<style lang="scss" scoped>
+.el-menu-vertical-demo:not(.el-menu--collapse) {
+  width: 200px;
+  // min-height: 400px;
+  user-select: none;
+}
+.box-item {
+  height: 100vh;
+}
+:deep(.el-menu) {
+  // width: 100%;
+  height: 100%;
+  overflow: auto;
+  // background: linear-gradient(
+  //   0deg,
+  //   rgba(134, 132, 255, 1) 0%,
+  //   rgba(60, 80, 232, 1) 100%
+  // );
+  background-color: rgba(48, 65, 86, 1);
+  box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.16);
+
+  .logo {
+    height: 65px;
+    color: rgb(255, 255, 255);
+    cursor: default;
+    display: flex;
+    justify-content: space-around;
+    align-items: center;
+  }
+  .logo:hover {
+    background-color: transparent !important;
+  }
+
+  .el-sub-menu.is-active {
+    .el-sub-menu__title {
+      background-color: rgba(33, 44, 58, 1);
+    }
+  }
+
+  .el-icon {
+    margin-right: 10px;
+  }
+}
+
+.el-menu-item.is-active {
+  box-sizing: border-box;
+  background-color: rgba(33, 44, 58, 1);
+  color: #fff;
+}
+</style>

+ 366 - 0
src/layout/SidevarItem1.vue

@@ -0,0 +1,366 @@
+<template>
+  <div class="box-item">
+    <el-menu
+      class="el-menu-vertical-demo"
+      background-color="#293749"
+      text-color="#fff"
+      active-text-color="#fff"
+      :default-active="sidevarItem"
+      :collapse="isCollapse"
+      @open="handleOpen"
+      @close="handleClose"
+      @select="handleSelect"
+    >
+      <div class="logo el-menu-item">
+        <el-icon :size="20"
+          ><img src="@/assets/img/logo.png" style="width: 40px; height: 40px"
+        /></el-icon>
+      </div>
+      <div v-for="i in roles.list" :key="i.path">
+        <el-sub-menu
+          v-if="i.name == '房源管理' || i.name == '权限管理'"
+          :index="i.index"
+          popper-class="ceshi"
+          :teleported="true"
+        >
+          <template #title>
+            <SvgIcon :name="i.icon" color="#fff" size="22"></SvgIcon>
+            <span>{{ i.name }}</span>
+          </template>
+          <el-menu-item
+            v-for="item in i.children"
+            :index="item.path"
+            :key="item.paht"
+          >
+            <template #title>{{ item.name }}</template>
+          </el-menu-item>
+        </el-sub-menu>
+        <el-menu-item v-else :index="i.path">
+          <SvgIcon :name="i.icon" color="#fff" size="22"></SvgIcon>
+          <template #title>{{ i.name }}</template>
+        </el-menu-item>
+      </div>
+
+      <!-- <el-menu-item index="/dataOverview">
+        <SvgIcon name="dataOverview" color="#fff" size="22"></SvgIcon>
+        <template #title>数据总览</template>
+      </el-menu-item>
+
+      <el-menu-item index="/studentInfo">
+        <SvgIcon name="studentInfo" color="#fff" size="22"></SvgIcon>
+        <template #title>学生信息管理</template>
+      </el-menu-item>
+
+      <el-sub-menu index="1" popper-class="ceshi" :teleported="true">
+        <template #title>
+          <SvgIcon name="building" color="#fff" size="22"></SvgIcon>
+          <span>房源管理</span>
+        </template>
+        <el-menu-item index="/building">
+          <template #title>楼栋信息管理</template>
+        </el-menu-item>
+        <el-menu-item index="/dormitory">
+          <template #title>寝室信息管理</template>
+        </el-menu-item>
+        <el-menu-item index="/bed">
+          <template #title>床位信息管理</template>
+        </el-menu-item>
+      </el-sub-menu>
+
+      <el-menu-item index="/student">
+        <SvgIcon name="student" color="#fff" size="22"></SvgIcon>
+        <template #title>学生住宿信息</template>
+      </el-menu-item>
+      <el-menu-item index="/quarterage">
+        <SvgIcon name="quarterage" color="#fff" size="22"></SvgIcon>
+        <template #title>住宿信息统计</template>
+      </el-menu-item>
+      <el-menu-item index="/caller">
+        <SvgIcon name="caller" color="#fff" size="22"></SvgIcon>
+        <template #title>访客信息管理</template>
+      </el-menu-item>
+      <el-sub-menu index="2" popper-class="ceshi" :teleported="true">
+        <template #title>
+          <SvgIcon name="role" color="#fff" size="22"></SvgIcon>
+          <span>权限管理</span>
+        </template>
+        <el-menu-item index="/user">
+          <template #title>用户管理</template>
+        </el-menu-item>
+        <el-menu-item index="/role">
+          <template #title>角色管理</template>
+        </el-menu-item>
+      </el-sub-menu>
+      <el-menu-item index="/system">
+        <SvgIcon name="system" color="#fff" size="22"></SvgIcon>
+        <template #title>系统设置</template>
+      </el-menu-item> -->
+    </el-menu>
+  </div>
+</template>
+
+<script setup>
+import { ref, onBeforeMount, onMounted, watch, reactive } from "vue";
+import {
+  Fold,
+  Expand,
+  Service,
+  Position,
+  View,
+  Open,
+} from "@element-plus/icons-vue";
+import { useRouter } from "vue-router";
+import { storeToRefs } from "pinia";
+import { useCounterStore } from "@/stores/index";
+
+const store = useCounterStore();
+const { isCollapse, sidevarItem, roleList } = storeToRefs(store);
+
+const router = useRouter();
+const roles = reactive({
+  list: [],
+});
+
+const acitveItems = reactive({ list: [] });
+
+const handleSelect = (key) => {
+  console.log(key);
+
+  store.setItem(key);
+  router.push({
+    path: `${key}`,
+  });
+};
+const handleOpen = () => {};
+const handleClose = () => {};
+onMounted(() => {
+  console.log(roleList.value);
+  roleList.value.forEach((i) => {
+    if (i.path == "/building" || i.path == "/dormitory" || i.path == "/bed") {
+      const exists = roles.list.some((item) => item.name === "房源管理");
+      if (exists) {
+        roles.list.forEach((j) => {
+          if (j.name == "房源管理") {
+            j.children.push({
+              name: i.name,
+              path: i.path,
+              icon: i.icon,
+            });
+          }
+        });
+      } else {
+        roles.list.push({
+          name: "房源管理",
+          index: 1,
+          icon: "building",
+          children: [
+            {
+              name: i.name,
+              path: i.path,
+              icon: i.icon,
+            },
+          ],
+        });
+      }
+    } else if (i.path == "/user" || i.path == "/role") {
+      const exists = roles.list.some((item) => item.name === "权限管理");
+      if (exists) {
+        roles.list.forEach((j) => {
+          if (j.name == "权限管理") {
+            j.children.push({
+              name: i.name,
+              path: i.path,
+              icon: i.icon,
+            });
+          }
+        });
+      } else {
+        roles.list.push({
+          name: "权限管理",
+          index: 2,
+          icon: "role",
+          children: [
+            {
+              name: i.name,
+              path: i.path,
+              icon: i.icon,
+            },
+          ],
+        });
+      }
+    } else {
+      roles.list.push({
+        name: i.name,
+        path: i.path,
+        icon: i.icon,
+      });
+    }
+  });
+  console.log(roles.list);
+});
+onBeforeMount(() => {
+  // console.log("SidevarItem/onBeforeMount");
+});
+</script>
+
+<style lang="scss" scoped>
+.el-menu-vertical-demo:not(.el-menu--collapse) {
+  width: 200px;
+  // min-height: 400px;
+  user-select: none;
+}
+.box-item {
+  height: 100vh;
+}
+:deep(.el-menu--vertical) {
+  height: 100%;
+  overflow: auto;
+  background-color: rgba(48, 65, 86, 1);
+  box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.16);
+
+  .logo {
+    height: 65px;
+    color: rgb(255, 255, 255);
+    cursor: default;
+    display: flex;
+    justify-content: space-around;
+    align-items: center;
+    margin: 20px 0 !important;
+  }
+  .logo:hover {
+    background-color: transparent !important;
+  }
+
+  .el-sub-menu {
+    padding: 0 14px;
+    margin-bottom:20px ;
+    .el-sub-menu__title {
+      height: 40px;
+      // margin: 0 0 20px 0;
+      margin: 0;
+      border-radius: 10px;
+    }
+    .el-menu-item {
+      height: 40px;
+      margin: 20px 0 !important;
+      border-radius: 10px;
+      .el-menu-tooltip__trigger {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+      &:last-child {
+        margin: 20px 0 0 0 !important;
+      }
+      &.is-active {
+        background: linear-gradient(
+          90deg,
+          rgba(38, 151, 255, 1) 0%,
+          rgba(102, 182, 255, 1) 100%
+        );
+      }
+    }
+    .el-menu.el-menu--inline {
+      box-shadow: none;
+      background-color: rgba(48, 65, 86, 1);
+    }
+    &.is-active.is-opened {
+      .el-sub-menu__title {
+        background: linear-gradient(
+          90deg,
+          rgba(38, 151, 255, 1) 0%,
+          rgba(102, 182, 255, 1) 100%
+        );
+      }
+    }
+  }
+
+  .el-menu-item {
+    height: 40px;
+    margin: 20px 14px;
+    border-radius: 10px;
+    .el-menu-tooltip__trigger {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+    }
+    &.is-active {
+      background: linear-gradient(
+        90deg,
+        rgba(38, 151, 255, 1) 0%,
+        rgba(102, 182, 255, 1) 100%
+      );
+    }
+  }
+}
+:deep(.el-menu--collapse) {
+  .el-sub-menu {
+    padding: 0;
+    margin: 20px 10px;
+    .el-sub-menu__title {
+      span {
+        display: none;
+      }
+      .el-icon {
+        margin-right: 0;
+      }
+      .el-sub-menu__icon-arrow {
+        display: none;
+      }
+    }
+  }
+  .el-sub-menu.is-active {
+    .el-sub-menu__title {
+      background: linear-gradient(
+        90deg,
+        rgba(38, 151, 255, 1) 0%,
+        rgba(102, 182, 255, 1) 100%
+      );
+      span {
+        display: none;
+      }
+    }
+  }
+  .el-sub-menu {
+    padding: 0;
+    margin: 0 10px 20px !important;
+    .el-sub-menu__title {
+      width: 40px;
+      padding: 0 20px;
+      // margin: 0 0 20px 0;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+    }
+  }
+  .el-sub-menu {
+    .el-menu-item {
+      border: 1px solid red;
+    }
+  }
+  .el-menu-item {
+    width: 40px;
+    margin: 20px 10px;
+    .el-menu-tooltip__trigger {
+      .el-icon {
+        margin-right: 0;
+      }
+    }
+  }
+}
+</style>
+
+<style lang="scss">
+.ceshi {
+  &.is-light {
+    border: none !important;
+  }
+  .el-menu-item.is-active {
+    background: linear-gradient(
+      90deg,
+      rgba(38, 151, 255, 1) 0%,
+      rgba(102, 182, 255, 1) 100%
+    );
+  }
+}
+</style>

+ 150 - 0
src/layout/SidevarItem报修.vue

@@ -0,0 +1,150 @@
+<template>
+  <div class="box-item">
+    <el-menu
+      class="el-menu-vertical-demo"
+      background-color="#293749"
+      text-color="#fff"
+      active-text-color="#fff"
+      :default-active="sidevarItem"
+      :collapse="isCollapse"
+      @open="handleOpen"
+      @close="handleClose"
+      @select="handleSelect"
+    >
+      <div class="logo el-menu-item">
+        <el-icon :size="20"
+          ><img src="@/assets/img/logo.png" style="width: 30px; height: 24px"
+        /></el-icon>
+      </div>
+
+      <!-- <el-sub-menu index="1">
+        <template #title>
+          <SvgIcon name="apple" color="#fff" size="22"></SvgIcon>
+          <span>项目</span>
+        </template>
+        <el-menu-item index="/a">
+          <SvgIcon name="star" color="#fff" size="18"></SvgIcon>
+          <template #title>项目一</template>
+        </el-menu-item>
+        <el-menu-item index="/b">
+          <SvgIcon name="month" color="#fff" size="18"></SvgIcon>
+          <template #title>项目二</template>
+        </el-menu-item>
+        <el-menu-item index="/c">
+          <SvgIcon name="sun" color="#fff" size="18"></SvgIcon>
+          <template #title>项目三</template>
+        </el-menu-item>
+      </el-sub-menu> -->
+      <el-menu-item index="/home">
+        <SvgIcon name="home" color="#fff" size="22"></SvgIcon>
+        <template #title>首页</template>
+      </el-menu-item>
+      <el-menu-item index="/account">
+        <SvgIcon name="student" color="#fff" size="22"></SvgIcon>
+        <template #title>账号管理</template>
+      </el-menu-item>
+      <el-menu-item index="/role">
+        <SvgIcon name="info" color="#fff" size="22"></SvgIcon>
+        <template #title>角色管理</template>
+      </el-menu-item>
+      <el-menu-item index="/permission">
+        <SvgIcon name="teacher" color="#fff" size="22"></SvgIcon>
+        <template #title>菜单权限管理</template>
+      </el-menu-item>
+      <!-- <el-menu-item index="/info">
+        <SvgIcon name="info" color="#fff" size="22"></SvgIcon>
+        <template #title>个人信息</template>
+      </el-menu-item> -->
+    </el-menu>
+  </div>
+</template>
+
+<script setup>
+import { ref, onBeforeMount, onMounted, watch, reactive } from "vue";
+import {
+  Fold,
+  Expand,
+  Service,
+  Position,
+  View,
+  Open,
+} from "@element-plus/icons-vue";
+import { useRouter } from "vue-router";
+import { storeToRefs } from "pinia";
+import { useCounterStore } from "@/stores/index";
+
+const store = useCounterStore();
+const { isCollapse, sidevarItem, roleList } = storeToRefs(store);
+
+const router = useRouter();
+
+const acitveItems = reactive({ list: [] });
+
+const handleSelect = (key) => {
+  store.setItem(key);
+  router.push({
+    path: `${key}`,
+  });
+};
+const handleOpen = () => {};
+const handleClose = () => {};
+onBeforeMount(() => {
+  // console.log("SidevarItem/onBeforeMount");
+  acitveItems.list = JSON.parse(localStorage.getItem("permissionList")) || [];
+});
+</script>
+
+<style lang="scss" scoped>
+.el-menu-vertical-demo:not(.el-menu--collapse) {
+  width: 200px;
+  // min-height: 400px;
+  user-select: none;
+}
+.box-item {
+  height: 100vh;
+}
+:deep(.el-menu) {
+  // width: 100%;
+  height: 100%;
+  overflow: auto;
+  // background: linear-gradient(
+  //   0deg,
+  //   rgba(134, 132, 255, 1) 0%,
+  //   rgba(60, 80, 232, 1) 100%
+  // );
+  background-color: rgba(48, 65, 86, 1);
+  box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.16);
+
+  .logo {
+    height: 65px;
+    color: rgb(255, 255, 255);
+    cursor: default;
+    display: flex;
+    justify-content: space-around;
+    align-items: center;
+  }
+  .logo:hover {
+    background-color: transparent !important;
+  }
+
+  .el-sub-menu.is-active {
+    .el-sub-menu__title {
+      background-color: rgba(33, 44, 58, 1);
+    }
+  }
+  // .el-sub-menu {
+  //   .el-menu-item {
+  //     // padding:0 0 0 65px !important;
+  //   }
+  // }
+  .el-icon {
+    margin-right: 10px;
+  }
+}
+
+.el-menu-item.is-active {
+  box-sizing: border-box;
+  background-color: rgba(33, 44, 58, 1);
+  color: #fff;
+}
+</style>

+ 60 - 0
src/main.js

@@ -0,0 +1,60 @@
+import { createApp } from "vue";
+import "./style.css";
+import App from "./App.vue";
+
+import ElementPlus from "element-plus";
+import "element-plus/dist/index.css";
+import zhCn from "element-plus/es/locale/lang/zh-cn";
+
+import router from "./router";
+
+import { createPinia } from "pinia";
+import { useCounterStore } from "@/stores/index";
+
+// 导入 SVG 图标样式和注册逻辑
+import 'virtual:svg-icons-register'
+import SvgIcon from "@/components/SvgIcon.vue"; // 导入SvgIcon组件
+
+import Viewer from "v-viewer";
+import "viewerjs/dist/viewer.css";
+
+
+const addRouter = async () => {
+  const store = useCounterStore();
+  await store.ROLEAdd();
+};
+async function call() {
+  const app = createApp(App);
+
+  app.use(ElementPlus, {
+    locale: zhCn,
+  });
+
+  app.component("SvgIcon", SvgIcon); // 全局注册SvgIcon组件
+
+  app.use(createPinia());
+  // await addRouter();// 动态添加路由的时候刷新页面会重新调用,防止刷新页面空白
+  app.use(router);
+
+  app.use(Viewer, {
+    Options: {
+      inline: true,
+      button: true, //右上角按钮
+      navbar: true, //底部缩略图
+      title: true, //当前图片标题
+      toolbar: true, //底部工具栏
+      tooltip: true, //显示缩放百分比
+      movable: true, //是否可以移动
+      zoomable: true, //是否可以缩放
+      rotatable: true, //是否可旋转
+      scalable: true, //是否可翻转
+      transition: true, //使用 CSS3 过度
+      fullscreen: true, //播放时是否全屏
+      keyboard: true, //是否支持键盘
+      url: "data-source",
+    },
+  });
+
+  app.mount("#app");
+}
+call();

+ 146 - 0
src/router/index.js

@@ -0,0 +1,146 @@
+// src/router/index.ts
+import { createRouter, createWebHistory } from "vue-router";
+import NProgress from "nprogress";
+import "nprogress/nprogress.css"; // 引入 NProgress 的 CSS 样式文件
+import { ElMessage } from "element-plus";
+const routes = [
+  {
+    path: "/login",
+    name: "login",
+    meta: { title: "", icon: "", showHeader: false },
+    component: () => import("@/views/login/login.vue"),
+  },
+  {
+    path: "/",
+    redirect: "/login",
+  },
+  // 校友信息管理
+  {
+    path: "/alumni-info",
+    component: () => import("@/views/alumni-info/alumni-info.vue"),
+    meta: { title: "校友信息管理", icon: "el-icon-user",showHeader: true },
+  },
+  // 校友组织管理
+  {
+    path: "/alumni-organization",
+    component: () =>
+      import("@/views/alumni-organization/alumni-organization.vue"),
+    meta: { title: "校友组织管理", icon: "el-icon-s-tools",showHeader: true },
+  },
+  // 校友活动管理
+  {
+    path: "/alumni-activity",
+    component: () => import("@/views/alumni-activity/alumni-activity.vue"),
+    meta: { title: "校友活动管理", icon: "el-icon-date",showHeader: true },
+  },
+  // 广场信息管理
+  {
+    path: "/alumni-square",
+    component: () => import("@/views/alumni-square/alumni-square.vue"),
+    meta: { title: "广场信息管理", icon: "el-icon-chat-dot-round",showHeader: true },
+  },
+  // 校友合作管理
+  {
+    path: "/alumni-cooperation",
+    component: () =>
+      import("@/views/alumni-cooperation/alumni-cooperation.vue"),
+    meta: { title: "校友合作管理", icon: "el-icon-s-data",showHeader: true },
+  },
+  // 校友企业管理
+  {
+    path: "/alumni-enterprise",
+    component: () => import("@/views/alumni-enterprise/alumni-enterprise.vue"),
+    meta: { title: "校友企业管理", icon: "el-icon-office-building",showHeader: true },
+  },
+  // 校友风采管理
+  {
+    path: "/alumni-style",
+    component: () => import("@/views/alumni-style/alumni-style.vue"),
+    meta: { title: "校友风采管理", icon: "el-icon-user-solid",showHeader: true },
+  },
+  // 新闻聚焦管理
+  {
+    path: "/alumni-new",
+    component: () => import("@/views/alumni-new/alumni-new.vue"),
+    meta: { title: "新闻聚焦管理", icon: "el-icon-document",showHeader: true },
+  },
+  // 返校服务管理
+  {
+    path: "/homecoming-service",
+    component: () =>
+      import("@/views/homecoming-service/homecoming-service.vue"),
+    meta: { title: "返校服务管理", icon: "el-icon-house",showHeader: true },
+  },
+  // 电子校友卡管理
+  {
+    path: "/alumni-card",
+    component: () => import("@/views/alumni-card/alumni-card.vue"),
+    meta: { title: "电子校友卡管理", icon: "el-icon-ticket",showHeader: true },
+  },
+  // 校友相册管理
+  {
+    path: "/alumni-album",
+    component: () => import("@/views/alumni-album/alumni-album.vue"),
+    meta: { title: "校友相册管理", icon: "el-icon-picture" ,showHeader: true},
+  },
+  // 权限管理
+  {
+    path: "/permission",
+    component: () => import("@/views/permission/permission.vue"),
+    meta: { title: "权限管理", icon: "el-icon-lock",showHeader: true },
+  },
+  // 操作日志
+  {
+    path: "/operation-log",
+    component: () => import("@/views/operation-log/operation-log.vue"),
+    meta: { title: "操作日志", icon: "el-icon-document-copy",showHeader: true },
+  },
+  // 系统设置
+  {
+    path: "/system-setting",
+    component: () => import("@/views/system-setting/system-setting.vue"),
+    meta: { title: "系统设置", icon: "el-icon-setting",showHeader: true },
+  },
+  {
+    path: "/:pathMatch(.*)*",
+    redirect: "/404",
+  },
+];
+const router = createRouter({
+  history: createWebHistory(),
+  routes,
+});
+
+// 配置 NProgress
+NProgress.configure({ showSpinner: false }); // 根据需要配置选项
+
+// 在路由守卫中启动和停止 NProgress
+router.beforeEach(async (to, from, next) => {
+  NProgress.start(); // 开始加载进度条
+
+  let token = sessionStorage.getItem("token");
+  // if (to.path == "/login") {
+  //   next();
+  // } else {
+  //   if (token) {
+  //     next();
+  //   } else {
+  //     ElMessage({
+  //       type: "error",
+  //       showClose: true,
+  //       message: "无权限进入此页面",
+  //       center: true,
+  //     });
+  //     sessionStorage.removeItem("token")// 移出token
+  //     sessionStorage.removeItem("id")// 移出用户id
+  //     sessionStorage.removeItem("permissionList")// 移出权限列表
+  //     sessionStorage.removeItem("permissionListFlat")
+  //     next("/login");
+  //   }
+  // }
+  next();
+});
+router.afterEach(() => {
+  NProgress.done(); // 结束加载进度条
+});
+export default router;

+ 80 - 0
src/stores/index.js

@@ -0,0 +1,80 @@
+// src/stores/counter.ts
+import { defineStore } from "pinia";
+import router from "@/router";
+export const useCounterStore = defineStore("user", {
+  state: () => {
+    return {
+      account: "", // 用户名
+      token: "", // toekn
+      isCollapse: false, // 侧边栏折叠状态
+      menuActive: "/home", // 侧边栏默认选中
+      roleList: [], // 菜单权限列表
+    };
+  },
+  getters: {
+    realAge(state) {
+      return state.age * 10;
+    },
+  },
+  actions: {
+    setAge({ name, age }) {
+      this.$patch({
+        name,
+        age,
+      });
+    },
+    // 控制侧边栏的伸缩
+    setInfo(isCollapse) {
+      this.isCollapse = isCollapse;
+    },
+    // 保存菜单项
+    SETMENU(menuActive) {
+      console.log(menuActive,"setTtem");
+      
+      this.menuActive = menuActive;
+      sessionStorage.setItem("menuActive", menuActive);
+    },
+    //router/index.js  动态添加路由
+    async ROLEAdd(roleList) {
+      // 获取菜单权限列表
+      // roleList = JSON.parse(localStorage.getItem("permissionList")) || [];
+      // const modules = import.meta.glob("../views/**/*.vue");
+
+      // roleList.forEach((i) => {
+      //   if (i.type == 2) {
+      //     let arr = {
+      //       path: `/${i.url}`,
+      //       name: i.permissionName,
+      //       meta: { isAuth: true, title: i.permissionName, showHeader: true },
+      //       component: modules[`../views/${i.url}/${i.url}.vue`],
+      //     };
+      //     router.addRoute(arr);
+      //   } else if (i.type == 1) {
+      //     if (i.children != null) {
+      //       i.children.forEach((j) => {
+      //         if (j.type == 2) {
+      //           let arr = {
+      //             path: `/${j.url}`,
+      //             name: j.permissionName,
+      //             meta: {
+      //               isAuth: true,
+      //               title: j.permissionName,
+      //               showHeader: true,
+      //             },
+      //             component: modules[`../views/${j.url}/${j.url}.vue`],
+      //           };
+      //           router.addRoute(arr);
+      //         }
+      //       });
+      //     }
+      //   }
+      // });
+      // // 添加404页面
+      // router.addRoute({
+      //   path: "/404",
+      //   name: "NotFound",
+      //   component: () => import("@/views/404/404.vue"),
+      // });
+    },
+  },
+});

+ 79 - 0
src/style.css

@@ -0,0 +1,79 @@
+:root {
+  font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
+  line-height: 1.5;
+  font-weight: 400;
+
+  color-scheme: light dark;
+  color: rgba(255, 255, 255, 0.87);
+  background-color: #242424;
+
+  font-synthesis: none;
+  text-rendering: optimizeLegibility;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+a {
+  font-weight: 500;
+  color: #646cff;
+  text-decoration: inherit;
+}
+a:hover {
+  color: #535bf2;
+}
+
+body {
+  margin: 0;
+  display: flex;
+  place-items: center;
+  min-width: 320px;
+  min-height: 100vh;
+}
+
+h1 {
+  font-size: 3.2em;
+  line-height: 1.1;
+}
+
+button {
+  border-radius: 8px;
+  border: 1px solid transparent;
+  padding: 0.6em 1.2em;
+  font-size: 1em;
+  font-weight: 500;
+  font-family: inherit;
+  background-color: #1a1a1a;
+  cursor: pointer;
+  transition: border-color 0.25s;
+}
+button:hover {
+  border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+  outline: 4px auto -webkit-focus-ring-color;
+  outline: none;
+}
+
+.card {
+  padding: 2em;
+}
+
+#app {
+  margin: 0 auto;
+  padding: 2rem;
+  text-align: center;
+}
+
+@media (prefers-color-scheme: light) {
+  :root {
+    color: #213547;
+    background-color: #ffffff;
+  }
+  a:hover {
+    color: #747bff;
+  }
+  button {
+    background-color: #f9f9f9;
+  }
+}

+ 1 - 0
src/styles/mixin.scss

@@ -0,0 +1 @@
+$default: red

+ 82 - 0
src/utils/request.js

@@ -0,0 +1,82 @@
+import axios from "axios";
+import { ElMessage, ElMessageBox } from "element-plus";
+import router from "@/router/index";
+
+// 创建 axios 实例
+const service = axios.create({
+  // 基础路径,对应后端接口前缀(根据你的项目修改)
+  // baseURL: import.meta.env.VITE_API_BASE_URL,
+  // 请求超时时间
+  timeout: 10000,
+});
+
+
+// ===================== 请求拦截器(发送请求前做的事) =====================
+// 作用:给所有请求头添加 Token,供后端校验身份
+service.interceptors.request.use(
+  (config) => {
+    // 1. 从 localStorage 获取 Token(登录时存入的)
+    const token = sessionStorage.getItem("token");
+    // 2. 如果有 Token,添加到请求头(后端要通过这个头获取 Token)
+    if (token) {
+      config.headers["token"] = `${token}`;
+    }
+    // 3. 设置请求头格式(默认 JSON)
+    // if (!config.headers['Content-Type']) {
+    //   config.headers['Content-Type'] = 'application/json;charset=utf-8'
+    // }
+    return config;
+  },
+  (error) => {
+    // 请求出错时的处理(比如网络错误)
+    console.error("请求拦截器错误:", error);
+    return Promise.reject(error);
+  },
+);
+
+// ===================== 响应拦截器(收到后端响应后做的事) =====================
+// 作用:统一处理后端返回结果,简化组件内的调用逻辑
+service.interceptors.response.use(
+  (response) => {
+    // console.log(response);
+    if (response.data.message == "登录凭证已失效,请重新登录") {
+      router.push("/login");
+    } 
+      // 1. 获取后端返回的数据(response.data 是后端真正返回的内容)
+      const res = response.data;
+      return res;
+  },
+  (error) => {
+    // 3. 处理 HTTP 状态码错误(比如 401 未登录、403 权限不足、500 服务器错误)
+    console.error("响应拦截器错误:", error);
+    let msg = "";
+    // 获取 HTTP 状态码
+    const status = error.response?.status || 0;
+    switch (status) {
+      case 401:
+        // 401:Token 过期/无效 → 提示用户,清除 Token,跳登录页
+        msg = "登录已过期,请重新登录";
+        localStorage.removeItem("token");
+        router.push("/login");
+        break;
+      case 403:
+        // 403:权限不足 → 提示用户
+        msg = "权限不足,无法操作";
+        break;
+      case 500:
+        // 500:服务器内部错误 → 提示用户
+        msg = "服务器内部错误,请稍后重试";
+        break;
+      default:
+        // 其他错误:默认提示
+        msg = error.message || "请求出错,请稍后重试";
+    }
+    // 弹出错误提示
+    ElMessage.error(msg);
+    // 抛出错误
+    return Promise.reject(error);
+  },
+);
+
+// 导出封装好的 axios 实例
+export default service;

+ 20 - 0
src/utils/rsa.js

@@ -0,0 +1,20 @@
+import { JSEncrypt } from "jsencrypt";
+let publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMOcPB06u5yKyQsPjfVWiWgbEIrd14kiXNNihciaVKb6HnkQvq7zpQuZ80WEX94spnUMI3iOAl/GmIvHrpGwcbB4hJbznm+PajiwnUSPuCCXA68YJF640cJKb/8KeM7WVz69OFkIEPHhVxOy4FFF5QWe/kt6zOZ19HmE+ak+5x/QIDAQAB";
+let privateKey = "这里是封装的私钥";
+//加密方法
+export function RSAencrypt(pas) {
+    //实例化jsEncrypt对象
+    let jse = new JSEncrypt();
+    //设置公钥
+    jse.setPublicKey(publicKey);
+    // console.log("加密:" + jse.encrypt(pas));
+    return jse.encrypt(pas);
+}
+//解密方法
+export function RSAdecrypt(pas) {
+    let jse = new JSEncrypt();
+    // 私钥
+    jse.setPrivateKey(privateKey);
+    console.log("解密:" + jse.decrypt(pas));
+    return jse.decrypt(pas);
+}

+ 160 - 0
src/views/404/404.vue

@@ -0,0 +1,160 @@
+<template>
+  <div class="not-found-container">
+    <div class="not-found-content">
+      <!-- 404 图标或动画 -->
+      <div class="not-found-icon">
+        <svg xmlns="http://www.w3.org/2000/svg" width="120" height="120" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+          <circle cx="12" cy="12" r="10"></circle>
+          <line x1="12" y1="8" x2="12" y2="12"></line>
+          <line x1="12" y1="16" x2="12.01" y2="16"></line>
+        </svg>
+      </div>
+      
+      <!-- 标题和描述 -->
+      <h1 class="not-found-title">404</h1>
+      <h2 class="not-found-subtitle">页面未找到</h2>
+      <p class="not-found-description">
+        抱歉,您访问的页面不存在或已被移除。
+        <br>
+        请检查URL是否正确,或返回首页继续浏览。
+      </p>
+      
+      <!-- 操作按钮 -->
+      <div class="not-found-actions">
+        <router-link to="/home" class="home-button">
+          <span>返回首页</span>
+        </router-link>
+        <button @click="goBack" class="back-button">
+          <span>返回上一页</span>
+        </button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { useRouter } from 'vue-router'
+
+const router = useRouter()
+
+const goBack = () => {
+  if (window.history.length > 1) {
+    router.go(-1)
+  } else {
+    router.push('/')
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.not-found-container {
+  width: 100%;
+  height: 100vh;
+  background-size: cover;
+  background-size: 100% 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.not-found-content {
+  text-align: center;
+  max-width: 600px;
+  padding: 40px;
+  background-color: white;
+  border-radius: 12px;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
+}
+
+.not-found-icon {
+  margin-bottom: 24px;
+}
+
+.not-found-icon svg {
+  color: #6c757d;
+}
+
+.not-found-title {
+  font-size: 4rem;
+  font-weight: 700;
+  color: #343a40;
+  margin: 0 0 10px;
+}
+
+.not-found-subtitle {
+  font-size: 1.5rem;
+  font-weight: 500;
+  color: #495057;
+  margin: 0 0 20px;
+}
+
+.not-found-description {
+  font-size: 1rem;
+  color: #6c757d;
+  line-height: 1.6;
+  margin-bottom: 30px;
+}
+
+.not-found-actions {
+  display: flex;
+  justify-content: center;
+  gap: 16px;
+}
+
+.home-button, .back-button {
+  padding: 12px 24px;
+  border-radius: 6px;
+  font-weight: 500;
+  font-size: 1rem;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  text-decoration: none;
+  display: inline-flex;
+  align-items: center;
+}
+
+.home-button {
+  background-color: #3b82f6;
+  color: white;
+  border: none;
+}
+
+.home-button:hover {
+  background-color: #2563eb;
+}
+
+.back-button {
+  background-color: white;
+  color: #495057;
+  border: 1px solid #dee2e6;
+}
+
+.back-button:hover {
+  background-color: #f8f9fa;
+  border-color: #ced4da;
+}
+
+@media (max-width: 600px) {
+  .not-found-content {
+    padding: 30px 20px;
+  }
+  
+  .not-found-title {
+    font-size: 3rem;
+  }
+  
+  .not-found-subtitle {
+    font-size: 1.25rem;
+  }
+  
+  .not-found-actions {
+    flex-direction: column;
+    gap: 12px;
+  }
+  
+  .home-button, .back-button {
+    width: 100%;
+    justify-content: center;
+  }
+}
+</style>

+ 621 - 0
src/views/alumni-activity/ActivityAudit.vue

@@ -0,0 +1,621 @@
+<template>
+  <div class="scroll">
+    <div class="middle">
+      <div class="filter">
+        <div class="condition">
+          <span>报名人 :</span>
+          <el-input
+            clearable
+            v-model.trim="searchInput.name"
+            class="w-50 m-2"
+            placeholder="请输入发布人"
+            style="width: 180px"
+          />
+        </div>
+        <div class="condition">
+          <span>活动名称 :</span>
+          <el-input
+            clearable
+            v-model.trim="searchInput.name"
+            class="w-50 m-2"
+            placeholder="请输入活动名称"
+            style="width: 180px"
+          />
+        </div>
+        <div class="condition">
+          <span>所属组织 :</span>
+          <el-select
+            clearable
+            v-model="searchInput.name"
+            placeholder="请选择所属组织"
+          >
+            <el-option
+              v-for="i in collegeData"
+              :key="i.id"
+              :label="i.name"
+              :value="i.id"
+            />
+          </el-select>
+        </div>
+        <div class="condition">
+          <span>审核状态 :</span>
+          <el-select
+            clearable
+            v-model="searchInput.name"
+            placeholder="请选择审核状态"
+          >
+            <el-option
+              v-for="i in collegeData"
+              :key="i.id"
+              :label="i.name"
+              :value="i.id"
+            />
+          </el-select>
+        </div>
+        <div class="condition">
+          <span>审核时间 :</span>
+          <el-date-picker
+            v-model="searchInput.createTime"
+            unlink-panels
+            type="datetimerange"
+            range-separator="-"
+            start-placeholder="起始时间"
+            end-placeholder="结束时间"
+            format="YYYY-MM-DD HH:mm:ss"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            placeholder="请选择日期"
+          />
+        </div>
+        <el-button
+          style="margin-left: 20px"
+          color="rgba(38, 151, 255, 1)"
+          type="primary"
+          class="search"
+          @click="searchBtn"
+          ><span>查询</span></el-button
+        >
+        <el-button @click="resetBtn" plain color="rgba(43, 153, 255, 1)"
+          >重置</el-button
+        >
+      </div>
+    </div>
+    <div class="footer" v-loading="loading">
+      <el-table
+        :row-class-name="tableRowClassName"
+        :data="tableData.list"
+        @selection-change="handleSelectionChange"
+        style="width: 100%"
+        :header-cell-style="{
+          background: 'rgba(240, 243, 247, 1)',
+          height: '50px',
+          border: 0,
+        }"
+      >
+        <!-- <el-table-column type="selection" align="center" width="55" /> -->
+        <el-table-column type="index" align="center" label="序号" width="60" />
+        <el-table-column align="center" prop="school" label="报名人" />
+        <el-table-column align="center" prop="school" label="联系电话" />
+        <el-table-column align="center" prop="school" label="活动名称" />
+        <el-table-column align="center" prop="school" label="活动时间" />
+        <el-table-column align="center" prop="school" label="报名截止时间" />
+        <el-table-column align="center" prop="school" label="所属组织" />
+        <el-table-column align="center" prop="school" label="活动地点" />
+        <el-table-column align="center" prop="school" label="报名时间" />
+        <!-- <el-table-column width="100" align="center" label="组织城市">
+          <template #default="{ row }">
+            <span v-if="row.retentionState == 2">是</span>
+            <span v-if="row.retentionState == 1">否</span>
+          </template>
+        </el-table-column> -->
+        <el-table-column align="center" prop="sex" label="审核状态" />
+        <el-table-column align="center" prop="college" label="审核人" />
+        <el-table-column align="center" prop="college" label="审核时间" />
+        <el-table-column align="center" label="操作" fixed="right" width="200">
+          <template #default="{ row }">
+            <el-button type="primary" @click="updateS(row)" link
+              >详情</el-button
+            >
+            <el-button type="primary" @click="updateS(row)" link
+              >通过</el-button
+            >
+            <el-button type="danger" @click="deleteS(row)" link>拒绝</el-button>
+            <el-button type="danger" @click="deleteS(row)" link>删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页组件 -->
+      <div class="pageSize">
+        <span></span>
+        <el-pagination
+          background
+          :current-page="currentPage"
+          :page-size="pageSize"
+          :page-sizes="[10, 20, 30, 40]"
+          layout="total,sizes, prev, pager, next, jumper, slot"
+          :total="total"
+          @size-change="handleSizeChange"
+          @update:current-page="handleCurrentChange"
+        />
+      </div>
+    </div>
+  </div>
+  <!-- 添加账号弹窗 -->
+  <el-dialog
+    class="addStaff"
+    v-model="addDialogVisible"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    :title="dialongTitle"
+    align-center
+    width="560"
+    :before-close="cancelAdd"
+    destroy-on-close
+    draggable
+  >
+    <el-form
+      ref="ruleFormRef"
+      :model="ruleForm"
+      :rules="rules"
+      label-width="100px"
+      class="demo-ruleForm"
+      :size="formSize"
+      label-position="right"
+      status-icon
+    >
+      <el-form-item label="新闻标题 :" prop="dormitory">
+        <el-input
+          clearable
+          v-model.trim="ruleForm.dormitory"
+          class="w-50 m-2"
+          placeholder="请输入新闻标题"
+        />
+      </el-form-item>
+      <el-form-item label="新闻分类 :" prop="school">
+        <el-select
+          @change="schoolFormChange"
+          v-model="ruleForm.school"
+          clearable
+          placeholder="请选择新闻分类"
+        >
+          <el-option
+            v-for="i in schoolData"
+            :key="i.id"
+            :label="i.school"
+            :value="`${i.school},${i.id}`"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="新闻内容 :" prop="bedNumber">
+        <el-input
+          v-model.trim="ruleForm.bedNumber"
+          placeholder="请输入新闻内容"
+          clearable
+          :autosize="{ minRows: 4 }"
+          type="textarea"
+        />
+      </el-form-item>
+      <el-form-item class="options">
+        <el-button @click="cancelAdd">取消</el-button>
+        <el-button
+          color="rgba(0, 97, 255, 1)"
+          class="queding"
+          type="primary"
+          @click="submitAdd(ruleFormRef)"
+        >
+          确定
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </el-dialog>
+  <!-- 项目导入 -->
+  <el-dialog
+    class="projectImport"
+    v-model="buildImportVisible"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    title="寝室信息导入"
+    align-center
+    width="600"
+    :before-close="cancelProjectImport"
+  >
+    <!-- <p class="title">当前只支持项目类型为“非装配式建筑项目”的项目导入</p> -->
+    <p class="down">
+      <span>寝室信息导入模板下载</span
+      ><span @click="templateDown">模板下载</span>
+    </p>
+    <el-upload
+      class="avatar-uploader"
+      action="#"
+      :auto-upload="false"
+      :on-remove="projectImportRemove"
+      :on-change="projectImportChange"
+      :before-upload="beforeAvatarProImport"
+      ref="buildRef"
+      :limit="1"
+      :on-exceed="projectImportExceed"
+    >
+      <template #trigger>
+        <el-button class="queding" type="primary">
+          &nbsp;&nbsp;导入文件&nbsp;&nbsp;
+        </el-button>
+      </template>
+    </el-upload>
+    <div class="options">
+      <el-button
+        color="rgba(9, 101, 98, 1)"
+        class="queding"
+        type="primary"
+        @click="projectImportConfirm(buildRef)"
+        :loading="buildImportLoading"
+      >
+        &nbsp;&nbsp;确认导入&nbsp;&nbsp;
+      </el-button>
+      <el-button @click="cancelProjectImport"
+        >&nbsp;&nbsp;取消导入&nbsp;&nbsp;</el-button
+      >
+    </div>
+  </el-dialog>
+</template>
+
+<script setup>
+import {
+  ref,
+  watch,
+  reactive,
+  nextTick,
+  onBeforeMount,
+  onUnmounted,
+} from "vue";
+import { useRouter } from "vue-router";
+import { genFileId, ElMessage, ElMessageBox } from "element-plus";
+import { dayjs } from "element-plus";
+import lodash from "lodash";
+
+import { storeToRefs } from "pinia";
+import { useCounterStore } from "@/stores/index";
+
+const router = useRouter();
+const store = useCounterStore();
+
+// 为避免解构时失去响应性
+const { name, age, isCollapse, realAge, collegeRole } = storeToRefs(store);
+
+// 表格数据
+const loading = ref(false);
+const tableData = reactive({
+  list: [{}],
+});
+const activeIndex = ref(); // 默认跳转路由
+const dialongTitle = ref("新增账号"); // 弹窗标题
+
+const searchInput = reactive({
+  name: "",
+  year: null,
+  college: null,
+  major: null,
+  class: null,
+}); // 搜索按钮数据
+
+const currentPage = ref(1); // 当前页
+const pageSize = ref(10);
+const total = ref(0); // 当前总数
+const selectIds = ref([]); // 勾选的全部数据
+
+const addDialogVisible = ref(false); // 控制添加账号弹窗
+
+// 表单数据
+const formSize = ref("default");
+const ruleFormRef = ref();
+const ruleForm = reactive({
+  school: "靖安校区", //校区名称
+  build: "", //楼栋名称
+  dormitory: "", //寝室号
+  sex: "男", //寝室性别
+  college: "", //所属学院
+  major: "", //所属专业
+  bedNumber: "", //床位数
+  // "gradestr": "",              //所属年级
+  remark: "", //备注
+  id: "",
+});
+// 表单验证
+const rules = reactive({
+  school: [{ required: true, message: "校区名称不能为空", trigger: "blur" }],
+  build: [{ required: true, message: "楼栋名称不能为空", trigger: "blur" }],
+  dormitory: [{ required: true, message: "寝室号不能为空", trigger: "blur" }],
+  sex: [{ required: true, message: "寝室性别不能为空", trigger: "blur" }],
+  college: [{ required: true, message: "所属学院不能为空", trigger: "blur" }],
+  major: [{ required: true, message: "专业不能为空", trigger: "blur" }],
+  bedNumber: [{ required: true, message: "床位数不能为空", trigger: "blur" }],
+});
+
+// 获取账户列表
+const getList = async () => {
+  loading.value = true;
+  let params = {
+    currentPage: currentPage.value, // 当前页
+    pageCount: pageSize.value, // 一页数据条数
+    schoolId: searchInput.schoolId,
+    buildId: searchInput.buildId,
+  };
+};
+
+// 搜索功能
+const searchBtn = lodash.debounce(async () => {}, 300);
+const resetBtn = lodash.debounce(async () => {}, 300);
+
+// 添加账号
+const addlist = () => {
+  dialongTitle.value = "发布新闻";
+  addDialogVisible.value = true;
+  ruleForm.school = null;
+};
+// 添加账号
+const updateS = (row) => {
+  console.log(row);
+  dialongTitle.value = "编辑新闻";
+  addDialogVisible.value = true;
+};
+const deleteS = async (row) => {
+  ElMessageBox.confirm("是否删除此数据?", "提示!!!", {
+    confirmButtonText: "确认",
+    cancelButtonText: "取消",
+    type: "warning",
+  })
+    .then(async () => {
+      loading.value = true;
+      let data = {
+        dormitoryId: row.id, // 当前页
+      };
+    })
+    .catch(() => {
+      loading.value = false;
+    });
+};
+// 保留
+const retainS = async (row, flag) => {
+  let data = {
+    dormitoryIds: [row.id], // 当前页
+    retentionState: flag, //保留状态 1:开放,2:保留
+  };
+};
+
+// 确认添加员工
+const submitAdd = lodash.debounce(async (formEl) => {
+  if (!formEl) return;
+  await formEl.validate(async (valid, fields) => {
+    if (valid) {
+      console.log(data);
+    } else {
+      console.log("error submit!", fields);
+    }
+  });
+}, 1000);
+
+const cancelAdd = () => {
+  addDialogVisible.value = false;
+};
+
+// 多选框功能
+const handleSelectionChange = (val) => {
+  // console.log(val);
+  selectIds.value = val.map((i) => i.id);
+  console.log(selectIds.value);
+};
+
+// 表格斑马纹颜色修改
+const tableRowClassName = ({ row, rowIndex }) => {
+  if (rowIndex % 2 === 0) {
+    return "even";
+  } else if (rowIndex % 2 !== 0) {
+    return "odd";
+  }
+  return "";
+};
+// 每页显示条数
+const handleSizeChange = (value) => {
+  console.log(value, "每页显示条数");
+  pageSize.value = value;
+};
+// 分页
+const handleCurrentChange = (value) => {
+  // console.log(value);
+  currentPage.value = value;
+};
+
+const cancelProjectImport = () => {
+  buildImportVisible.value = false;
+  if (buildRef.value) {
+    buildRef.value.clearFiles();
+    buildFile.value = null;
+  }
+};
+
+onBeforeMount(() => {});
+onUnmounted(() => {
+  // document.removeEventListener("keyup", Enters);
+});
+</script>
+
+<style scoped lang="scss">
+.scroll {
+  width: calc(100% - 60px);
+  height: calc(100% - 61px);
+  margin: 0 auto;
+  display: flex;
+  flex-direction: column;
+
+  .middle {
+    width: calc(100%);
+    color: #000;
+    .filter {
+      display: flex;
+      flex-wrap: wrap;
+      align-items: center;
+      .search {
+        margin-left: 0 !important;
+        color: #fff;
+      }
+      .condition {
+        display: flex;
+        align-items: center;
+        margin: 10px 30px 10px 0;
+        :deep(.el-input .el-input__inner) {
+          font-size: 14px;
+        }
+        .el-select {
+          width: 220px;
+        }
+        span {
+          margin: 0 10px 0 0;
+        }
+      }
+    }
+    .gongneng {
+      margin: 10px 0;
+      .el-button {
+        color: #fff;
+        margin-right: 15px;
+      }
+    }
+  }
+  .footer {
+    width: calc(100%);
+    flex: 1;
+    margin: 0 auto;
+    overflow: auto;
+
+    .el-table--fit {
+      height: calc(100% - 60px);
+      :deep(.el-table__header-wrapper) {
+        background-color: #000;
+        font-size: 15px;
+        color: #000;
+        .cell {
+          color: #000;
+        }
+      }
+      :deep(.el-table__row) {
+        height: 50px;
+        font-size: 15px;
+        color: #000;
+      }
+      :deep(.el-table__row td) {
+        padding: 0;
+        border: 0;
+      }
+
+      .el-button--primary {
+        margin-left: 5px;
+      }
+      :deep(.el-table__body .even) {
+        background-color: #fff;
+      }
+      :deep(.el-table__body .odd) {
+        background-color: rgba(240, 243, 247, 1);
+      }
+      :deep(.options) {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        .open {
+          color: #2697ff;
+          cursor: pointer;
+          margin: 0 15px 0 0;
+        }
+        .edit {
+          margin: 0 15px 0 0;
+          color: #2697ff;
+          cursor: pointer;
+        }
+        .delete {
+          color: #f56c6c;
+          cursor: pointer;
+        }
+      }
+    }
+
+    .pageSize {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin: 0 30px;
+      height: 60px;
+
+      span {
+        color: #000;
+      }
+
+      .el-pagination {
+        // width: 1600px;
+        :deep(.el-pagination__total) {
+          color: #000;
+        }
+
+        :deep(.el-pagination__goto) {
+          color: #000;
+        }
+
+        :deep(.el-pagination__classifier) {
+          color: #000;
+        }
+
+        :deep(.el-input__wrapper) {
+          border: 1px solid rgba(0, 0, 0, 1);
+          border-radius: 5px;
+          box-shadow: none;
+        }
+
+        :deep(.el-pager li) {
+          margin: 0 5px;
+          border: 1px solid rgba(0, 0, 0, 1);
+          border-radius: 5px;
+          background-color: transparent;
+        }
+
+        :deep(.el-pager li.is-active) {
+          // background-color: rgba(0, 97, 255, 0.8);
+          border: 1px solid rgba(0, 97, 255, 1);
+          color: rgba(0, 97, 255, 1);
+        }
+
+        :deep(.btn-prev) {
+          margin-right: 5px;
+          border: 1px solid rgba(0, 0, 0, 1);
+          border-radius: 5px;
+          background-color: transparent;
+        }
+
+        :deep(.btn-next) {
+          margin-left: 5px;
+          border: 1px solid rgba(0, 0, 0, 1);
+          border-radius: 5px;
+          background-color: transparent;
+        }
+      }
+    }
+  }
+}
+
+// 添加员工弹窗样式
+:deep(.addStaff) {
+  .el-dialog__body {
+    padding: 20px 20px 10px 20px;
+    .el-input {
+      width: 400px;
+      .el-input__suffix-inner {
+        color: rgba(61, 81, 232, 1);
+      }
+    }
+    .el-textarea {
+      width: 400px;
+    }
+    .el-select {
+      width: 400px;
+    }
+    .el-tree {
+      width: 400px;
+    }
+  }
+}
+</style>

+ 700 - 0
src/views/alumni-activity/ActivityList.vue

@@ -0,0 +1,700 @@
+<template>
+  <div class="scroll">
+    <div class="middle">
+      <div class="filter">
+        <div class="condition">
+          <span>活动名称 :</span>
+          <el-input
+            clearable
+            v-model.trim="searchInput.name"
+            class="w-50 m-2"
+            placeholder="请输入活动名称"
+            style="width: 180px"
+          />
+        </div>
+        <div class="condition">
+          <span>活动状态 :</span>
+          <el-select
+            clearable
+            v-model="searchInput.name"
+            placeholder="请选择活动状态"
+          >
+            <el-option
+              v-for="i in collegeData"
+              :key="i.id"
+              :label="i.name"
+              :value="i.id"
+            />
+          </el-select>
+        </div>
+        <div class="condition">
+          <span>活动时间 :</span>
+          <el-date-picker
+            v-model="searchInput.createTime"
+            unlink-panels
+            type="datetimerange"
+            range-separator="-"
+            start-placeholder="起始时间"
+            end-placeholder="结束时间"
+            format="YYYY-MM-DD HH:mm:ss"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            placeholder="请选择日期"
+          />
+        </div>
+        <el-button
+          style="margin-left: 20px"
+          color="rgba(38, 151, 255, 1)"
+          type="primary"
+          class="search"
+          @click="searchBtn"
+          ><span>查询</span></el-button
+        >
+        <el-button @click="resetBtn" plain color="rgba(43, 153, 255, 1)"
+          >重置</el-button
+        >
+      </div>
+      <!-- 按钮列表 -->
+      <div class="gongneng">
+        <el-button
+          type="primary"
+          style="margin-left: 0"
+          color="rgba(38, 151, 255, 1)"
+          @click="addlist"
+          >创建活动</el-button
+        >
+      </div>
+    </div>
+    <div class="footer" v-loading="loading">
+      <el-table
+        :row-class-name="tableRowClassName"
+        :data="tableData.list"
+        @selection-change="handleSelectionChange"
+        style="width: 100%"
+        :header-cell-style="{
+          background: 'rgba(240, 243, 247, 1)',
+          height: '50px',
+          border: 0,
+        }"
+      >
+        <!-- <el-table-column type="selection" align="center" width="55" /> -->
+        <el-table-column type="index" align="center" label="序号" width="60" />
+        <el-table-column align="center" prop="school" label="活动名称" />
+        <el-table-column width="100" align="center" label="活动时间">
+          <template #default="{ row }">
+            <span v-if="row.retentionState == 2">是</span>
+            <span v-if="row.retentionState == 1">否</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          show-overflow-tooltip
+          align="center"
+          prop="dormitory"
+          label="活动地点"
+        />
+        <el-table-column
+          show-overflow-tooltip
+          align="center"
+          prop="dormitory"
+          label="活动详情"
+        />
+        <el-table-column align="center" prop="sex" label="报名截止时间" />
+        <el-table-column align="center" prop="college" label="所属组织" />
+        <el-table-column align="center" prop="major" label="发起人" />
+        <el-table-column align="center" prop="major" label="创建时间" />
+        <el-table-column align="center" prop="major" label="活动状态" />
+        <el-table-column align="center" prop="major" label="已报名" />
+        <el-table-column align="center" label="操作" fixed="right" width="200">
+          <template #default="{ row }">
+            <el-button type="primary" @click="updateS(row)" link
+              >编辑</el-button
+            >
+            <el-button type="danger" @click="deleteS(row)" link>删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页组件 -->
+      <div class="pageSize">
+        <span></span>
+        <el-pagination
+          background
+          :current-page="currentPage"
+          :page-size="pageSize"
+          :page-sizes="[10, 20, 30, 40]"
+          layout="total,sizes, prev, pager, next, jumper, slot"
+          :total="total"
+          @size-change="handleSizeChange"
+          @update:current-page="handleCurrentChange"
+        />
+      </div>
+    </div>
+  </div>
+  <!-- 添加账号弹窗 -->
+  <el-dialog
+    class="addStaff"
+    v-model="addDialogVisible"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    :title="dialongTitle"
+    align-center
+    width="580"
+    :before-close="cancelAdd"
+    destroy-on-close
+    draggable
+  >
+    <el-form
+      ref="ruleFormRef"
+      :model="ruleForm"
+      :rules="rules"
+      label-width="120px"
+      class="demo-ruleForm"
+      :size="formSize"
+      label-position="right"
+      status-icon
+    >
+      <el-form-item label="活动名称 :" prop="dormitory">
+        <el-input
+          clearable
+          v-model.trim="ruleForm.dormitory"
+          class="w-50 m-2"
+          placeholder="请输入活动名称"
+        />
+      </el-form-item>
+      <el-form-item label="所属组织 :" prop="school">
+        <el-select
+          @change="schoolFormChange"
+          v-model="ruleForm.school"
+          clearable
+          placeholder="请选择所属组织"
+        >
+          <el-option
+            v-for="i in schoolData"
+            :key="i.id"
+            :label="i.school"
+            :value="`${i.school},${i.id}`"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="活动详情 :" prop="bedNumber">
+        <el-input
+          v-model.trim="ruleForm.bedNumber"
+          placeholder="请输入活动详情"
+          clearable
+          :autosize="{ minRows: 4 }"
+          type="textarea"
+        />
+      </el-form-item>
+      <el-form-item label="活动时间 :" prop="dormitory">
+        <el-input
+          clearable
+          v-model.trim="ruleForm.dormitory"
+          class="w-50 m-2"
+          placeholder="请输入活动时间"
+        />
+      </el-form-item>
+      <el-form-item label="活动地点 :" prop="dormitory">
+        <el-input
+          clearable
+          v-model.trim="ruleForm.dormitory"
+          class="w-50 m-2"
+          placeholder="请输入活动地点"
+        />
+      </el-form-item>
+     <el-form-item label="报名截止时间 :" prop="dormitory">
+        <el-input
+          clearable
+          v-model.trim="ruleForm.dormitory"
+          class="w-50 m-2"
+          placeholder="请输入报名截止时间"
+        />
+      </el-form-item>
+      <el-form-item label="报名总人数 :" prop="dormitory">
+        <el-input
+          clearable
+          v-model.trim="ruleForm.dormitory"
+          class="w-50 m-2"
+          placeholder="请输入报名总人数"
+        />
+      </el-form-item>
+      <el-form-item class="options">
+        <el-button @click="cancelAdd">取消</el-button>
+        <el-button
+          color="rgba(0, 97, 255, 1)"
+          class="queding"
+          type="primary"
+          @click="submitAdd(ruleFormRef)"
+        >
+          确定
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </el-dialog>
+  <!-- 项目导入 -->
+  <el-dialog
+    class="projectImport"
+    v-model="buildImportVisible"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    title="寝室信息导入"
+    align-center
+    width="600"
+    :before-close="cancelProjectImport"
+  >
+    <!-- <p class="title">当前只支持项目类型为“非装配式建筑项目”的项目导入</p> -->
+    <p class="down">
+      <span>寝室信息导入模板下载</span
+      ><span @click="templateDown">模板下载</span>
+    </p>
+    <el-upload
+      class="avatar-uploader"
+      action="#"
+      :auto-upload="false"
+      :on-remove="projectImportRemove"
+      :on-change="projectImportChange"
+      :before-upload="beforeAvatarProImport"
+      ref="buildRef"
+      :limit="1"
+      :on-exceed="projectImportExceed"
+    >
+      <template #trigger>
+        <el-button class="queding" type="primary">
+          &nbsp;&nbsp;导入文件&nbsp;&nbsp;
+        </el-button>
+      </template>
+    </el-upload>
+    <div class="options">
+      <el-button
+        color="rgba(9, 101, 98, 1)"
+        class="queding"
+        type="primary"
+        @click="projectImportConfirm(buildRef)"
+        :loading="buildImportLoading"
+      >
+        &nbsp;&nbsp;确认导入&nbsp;&nbsp;
+      </el-button>
+      <el-button @click="cancelProjectImport"
+        >&nbsp;&nbsp;取消导入&nbsp;&nbsp;</el-button
+      >
+    </div>
+  </el-dialog>
+</template>
+
+<script setup>
+import {
+  ref,
+  watch,
+  reactive,
+  nextTick,
+  onBeforeMount,
+  onUnmounted,
+} from "vue";
+import { useRouter } from "vue-router";
+import { genFileId, ElMessage, ElMessageBox } from "element-plus";
+import { dayjs } from "element-plus";
+import lodash from "lodash";
+import { Delete, Download, Plus, ZoomIn } from "@element-plus/icons-vue";
+import { storeToRefs } from "pinia";
+import { useCounterStore } from "@/stores/index";
+import { api as viewerApi } from "v-viewer";
+
+const router = useRouter();
+const store = useCounterStore();
+
+// 为避免解构时失去响应性
+const { name, age, isCollapse, realAge, collegeRole } = storeToRefs(store);
+
+// 维护当前的文件列表
+const fileList = ref([]);
+
+// 核心:文件变化时直接覆盖
+const handleFileChange = (newFile) => {
+  // 直接用新文件替换整个列表,实现覆盖
+  fileList.value = [newFile];
+};
+
+// 上传前检查:如果已有文件,给出提示
+const handleBeforeUpload = () => {
+  if (fileList.value.length > 0) {
+    ElMessage.info("新图片将覆盖原有图片");
+  }
+  return true;
+};
+
+const handleRemove = () => {
+  fileList.value = [];
+  console.log("删除图片");
+};
+
+// 图片预览
+const handlePictureCardPreview = (file) => {
+  viewerApi({ images: fileList.value,zIndex: 2020 });
+};
+
+// 表格数据
+const loading = ref(false);
+const tableData = reactive({
+  list: [{}],
+});
+const activeIndex = ref(); // 默认跳转路由
+const dialongTitle = ref("新增账号"); // 弹窗标题
+
+const searchInput = reactive({
+  name: "",
+  year: null,
+  college: null,
+  major: null,
+  class: null,
+}); // 搜索按钮数据
+
+const currentPage = ref(1); // 当前页
+const pageSize = ref(10);
+const total = ref(0); // 当前总数
+const selectIds = ref([]); // 勾选的全部数据
+
+const addDialogVisible = ref(false); // 控制添加账号弹窗
+const options = ref([
+  {
+    value: "guide",
+    label: "Guide",
+    children: [
+      {
+        value: "disciplines",
+        label: "Disciplines",
+        children: [
+          {
+            value: "consistency",
+            label: "Consistency",
+          },
+          {
+            value: "feedback",
+            label: "Feedback",
+          },
+          {
+            value: "efficiency",
+            label: "Efficiency",
+          },
+          {
+            value: "controllability",
+            label: "Controllability",
+          },
+        ],
+      },
+      {
+        value: "navigation",
+        label: "Navigation",
+        children: [
+          {
+            value: "side nav",
+            label: "Side Navigation",
+          },
+          {
+            value: "top nav",
+            label: "Top Navigation",
+          },
+        ],
+      },
+    ],
+  },
+]);
+
+// 表单数据
+const formSize = ref("default");
+const ruleFormRef = ref();
+const ruleForm = reactive({
+  school: "靖安校区", //校区名称
+  build: "", //楼栋名称
+  dormitory: "", //寝室号
+  sex: "男", //寝室性别
+  college: "", //所属学院
+  major: "", //所属专业
+  bedNumber: "", //床位数
+  // "gradestr": "",              //所属年级
+  remark: "", //备注
+  id: "",
+});
+// 表单验证
+const rules = reactive({
+  school: [{ required: true, message: "校区名称不能为空", trigger: "blur" }],
+  build: [{ required: true, message: "楼栋名称不能为空", trigger: "blur" }],
+  dormitory: [{ required: true, message: "寝室号不能为空", trigger: "blur" }],
+  sex: [{ required: true, message: "寝室性别不能为空", trigger: "blur" }],
+  college: [{ required: true, message: "所属学院不能为空", trigger: "blur" }],
+  major: [{ required: true, message: "专业不能为空", trigger: "blur" }],
+  bedNumber: [{ required: true, message: "床位数不能为空", trigger: "blur" }],
+});
+
+// 获取账户列表
+const getList = async () => {
+  loading.value = true;
+  let params = {
+    currentPage: currentPage.value, // 当前页
+    pageCount: pageSize.value, // 一页数据条数
+    schoolId: searchInput.schoolId,
+    buildId: searchInput.buildId,
+  };
+};
+
+// 搜索功能
+const searchBtn = lodash.debounce(async () => {}, 300);
+const resetBtn = lodash.debounce(async () => {}, 300);
+
+const top = () => {};
+
+// 添加账号
+const addlist = () => {
+  dialongTitle.value = "创建组织";
+  addDialogVisible.value = true;
+  ruleForm.school = null;
+};
+// 添加账号
+const updateS = (row) => {
+  console.log(row);
+  dialongTitle.value = "编辑组织";
+  addDialogVisible.value = true;
+};
+const deleteS = async (row) => {
+  ElMessageBox.confirm("是否删除此数据?", "提示!!!", {
+    confirmButtonText: "确认",
+    cancelButtonText: "取消",
+    type: "warning",
+  })
+    .then(async () => {
+      loading.value = true;
+      let data = {
+        dormitoryId: row.id, // 当前页
+      };
+    })
+    .catch(() => {
+      loading.value = false;
+    });
+};
+// 保留
+const retainS = async (row, flag) => {
+  let data = {
+    dormitoryIds: [row.id], // 当前页
+    retentionState: flag, //保留状态 1:开放,2:保留
+  };
+};
+
+// 确认添加员工
+const submitAdd = lodash.debounce(async (formEl) => {
+  if (!formEl) return;
+  await formEl.validate(async (valid, fields) => {
+    if (valid) {
+      console.log(data);
+    } else {
+      console.log("error submit!", fields);
+    }
+  });
+}, 1000);
+
+const cancelAdd = () => {
+  addDialogVisible.value = false;
+};
+
+// 多选框功能
+const handleSelectionChange = (val) => {
+  // console.log(val);
+  selectIds.value = val.map((i) => i.id);
+  console.log(selectIds.value);
+};
+
+// 表格斑马纹颜色修改
+const tableRowClassName = ({ row, rowIndex }) => {
+  if (rowIndex % 2 === 0) {
+    return "even";
+  } else if (rowIndex % 2 !== 0) {
+    return "odd";
+  }
+  return "";
+};
+// 每页显示条数
+const handleSizeChange = (value) => {
+  console.log(value, "每页显示条数");
+  pageSize.value = value;
+};
+// 分页
+const handleCurrentChange = (value) => {
+  // console.log(value);
+  currentPage.value = value;
+};
+
+const cancelProjectImport = () => {
+  buildImportVisible.value = false;
+  if (buildRef.value) {
+    buildRef.value.clearFiles();
+    buildFile.value = null;
+  }
+};
+
+onBeforeMount(() => {});
+onUnmounted(() => {
+  // document.removeEventListener("keyup", Enters);
+});
+</script>
+
+<style scoped lang="scss">
+.scroll {
+  width: calc(100% - 60px);
+  height: calc(100% - 61px);
+  margin: 0 auto;
+  display: flex;
+  flex-direction: column;
+
+  .middle {
+    width: calc(100%);
+    color: #000;
+    .filter {
+      display: flex;
+      flex-wrap: wrap;
+      align-items: center;
+      .search {
+        margin-left: 0 !important;
+        color: #fff;
+      }
+      .condition {
+        display: flex;
+        align-items: center;
+        margin: 10px 30px 10px 0;
+        :deep(.el-input .el-input__inner) {
+          font-size: 14px;
+        }
+        .el-select {
+          width: 220px;
+        }
+        span {
+          margin: 0 10px 0 0;
+        }
+      }
+    }
+    .gongneng {
+      margin: 10px 0;
+      .el-button {
+        color: #fff;
+        margin-right: 15px;
+      }
+    }
+  }
+  .footer {
+    width: calc(100%);
+    flex: 1;
+    margin: 0 auto;
+    overflow: auto;
+
+    .el-table--fit {
+      height: calc(100% - 60px);
+      :deep(.el-table__header-wrapper) {
+        background-color: #000;
+        font-size: 15px;
+        color: #000;
+        .cell {
+          color: #000;
+        }
+      }
+      :deep(.el-table__row) {
+        height: 50px;
+        font-size: 15px;
+        color: #000;
+      }
+      :deep(.el-table__row td) {
+        padding: 0;
+        border: 0;
+      }
+
+      .el-button--primary {
+        margin-left: 5px;
+      }
+      :deep(.el-table__body .even) {
+        background-color: #fff;
+      }
+      :deep(.el-table__body .odd) {
+        background-color: rgba(240, 243, 247, 1);
+      }
+    }
+
+    .pageSize {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin: 0 30px;
+      height: 60px;
+
+      span {
+        color: #000;
+      }
+
+      .el-pagination {
+        // width: 1600px;
+        :deep(.el-pagination__total) {
+          color: #000;
+        }
+
+        :deep(.el-pagination__goto) {
+          color: #000;
+        }
+
+        :deep(.el-pagination__classifier) {
+          color: #000;
+        }
+
+        :deep(.el-input__wrapper) {
+          border: 1px solid rgba(0, 0, 0, 1);
+          border-radius: 5px;
+          box-shadow: none;
+        }
+
+        :deep(.el-pager li) {
+          margin: 0 5px;
+          border: 1px solid rgba(0, 0, 0, 1);
+          border-radius: 5px;
+          background-color: transparent;
+        }
+
+        :deep(.el-pager li.is-active) {
+          // background-color: rgba(0, 97, 255, 0.8);
+          border: 1px solid rgba(0, 97, 255, 1);
+          color: rgba(0, 97, 255, 1);
+        }
+
+        :deep(.btn-prev) {
+          margin-right: 5px;
+          border: 1px solid rgba(0, 0, 0, 1);
+          border-radius: 5px;
+          background-color: transparent;
+        }
+
+        :deep(.btn-next) {
+          margin-left: 5px;
+          border: 1px solid rgba(0, 0, 0, 1);
+          border-radius: 5px;
+          background-color: transparent;
+        }
+      }
+    }
+  }
+}
+
+// 添加员工弹窗样式
+.addStaff {
+  .el-dialog__body {
+    padding: 20px 20px 10px 20px;
+    .el-input {
+      width: 400px;
+    }
+    .el-textarea {
+      width: 400px;
+    }
+    .el-select {
+      width: 400px;
+    }
+    .el-form-item {
+      :deep(.el-form-item__content) {
+        .el-cascader {
+          .el-input {
+            width: 400px;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 93 - 0
src/views/alumni-activity/alumni-activity.vue

@@ -0,0 +1,93 @@
+<template>
+  <div class="content-box">
+    <div class="left">
+      <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
+        <el-tab-pane label="校友活动列表" name="first"></el-tab-pane>
+        <el-tab-pane label="活动报名审核" name="second"></el-tab-pane>
+      </el-tabs>
+    </div>
+    <template v-if="activeName == 'first'">
+      <ActivityList></ActivityList>
+    </template>
+    <template v-if="activeName == 'second'">
+      <ActivityAudit></ActivityAudit>
+    </template>
+  </div>
+</template>
+
+<script setup>
+import { ref, watch, reactive, onBeforeMount, onUnmounted } from "vue";
+import { useRouter } from "vue-router";
+import ActivityList from "./ActivityList.vue";
+import ActivityAudit from "./ActivityAudit.vue";
+
+import { storeToRefs } from "pinia";
+import { useCounterStore } from "@/stores/index";
+
+const router = useRouter();
+const store = useCounterStore();
+
+// 为避免解构时失去响应性
+const { name, age, isCollapse, realAge, collegeRole } = storeToRefs(store);
+
+const activeName = ref("first");
+
+const handleClick = (tab, event) => {
+  console.log(tab.props.name, event);
+};
+
+onBeforeMount(() => {});
+onUnmounted(() => {
+  // document.removeEventListener("keyup", Enters);
+});
+</script>
+
+<style scoped lang="scss">
+.content-box {
+  width: calc(100% - 40px);
+  height: calc(100% - 105px);
+  margin: 20px auto;
+  background-color: #fff;
+  color: #000;
+  display: flex;
+  flex-direction: column;
+
+  .svg {
+    width: 22px;
+    height: 22px;
+  }
+
+  .left {
+    width: calc(100% - 60px);
+    height: 60px;
+    margin: 0 auto;
+    display: flex;
+    align-items: center;
+    border-bottom: 1px solid #ccc;
+    color: #000;
+    font-size: 18px;
+    font-weight: 600;
+    .camera {
+      margin-right: 15px;
+      color: #4392f7;
+    }
+    :deep(.demo-tabs) {
+      .el-tabs__header {
+        margin: 0;
+        .el-tabs__nav-wrap::after {
+          display: none;
+        }
+        .el-tabs__item {
+          color: #000;
+          font-size: 18px;
+          font-weight: 600;
+          height: 60px;
+        }
+      }
+      .el-tabs__content {
+        display: none;
+      }
+    }
+  }
+}
+</style>

+ 0 - 0
src/views/alumni-activity/校友活动管理


+ 702 - 0
src/views/alumni-album/PhotoAudit.vue

@@ -0,0 +1,702 @@
+<template>
+  <div class="scroll">
+    <div class="middle">
+      <div class="filter">
+        <div class="condition">
+          <span>申请人 :</span>
+          <el-input
+            clearable
+            v-model.trim="searchInput.userName"
+            class="w-50 m-2"
+            placeholder="请输入申请人"
+            style="width: 180px"
+          />
+        </div>
+        <div class="condition">
+          <span>照片分类 :</span>
+          <el-select
+            clearable
+            v-model="searchInput.categoryId"
+            placeholder="请选择照片分类"
+          >
+            <el-option
+              v-for="i in categoryData"
+              :key="i.id"
+              :label="i.name"
+              :value="i.id"
+            />
+          </el-select>
+        </div>
+        <div class="condition">
+          <span>审核状态 :</span>
+          <el-select
+            clearable
+            v-model="searchInput.isPass"
+            placeholder="请选择审核状态"
+          >
+            <el-option label="通过" :value="2" />
+            <el-option label="拒绝" :value="3" />
+          </el-select>
+        </div>
+        <div class="condition">
+          <span>审核时间 :</span>
+          <el-date-picker
+            v-model="searchInput.createTime"
+            unlink-panels
+            type="datetimerange"
+            range-separator="-"
+            start-placeholder="起始时间"
+            end-placeholder="结束时间"
+            format="YYYY-MM-DD HH:mm:ss"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            placeholder="请选择日期"
+          />
+        </div>
+        <el-button
+          style="margin-left: 20px"
+          color="rgba(38, 151, 255, 1)"
+          type="primary"
+          class="search"
+          @click="searchBtn"
+          ><span>查询</span></el-button
+        >
+        <el-button @click="resetBtn" plain color="rgba(43, 153, 255, 1)"
+          >重置</el-button
+        >
+      </div>
+    </div>
+    <div class="footer" v-loading="loading">
+      <el-table
+        :row-class-name="tableRowClassName"
+        :data="tableData.list"
+        @selection-change="handleSelectionChange"
+        style="width: 100%"
+        :header-cell-style="{
+          background: 'rgba(240, 243, 247, 1)',
+          height: '50px',
+          border: 0,
+        }"
+      >
+        <!-- <el-table-column type="selection" align="center" width="55" /> -->
+        <el-table-column align="center" type="index" label="序号" width="60" />
+        <el-table-column align="center" prop="adminName" label="申请人" />
+        <el-table-column
+          width="120"
+          align="center"
+          prop="phone"
+          label="联系电话"
+        >
+        </el-table-column>
+        <el-table-column align="left" prop="dormitory" label="照片">
+          <template #default="{ row }">
+            <div class="img-preview-list" v-if="row.images">
+              <div
+                class="img-item"
+                style="width: 60px; height: 60px; margin: 10px 0"
+              >
+                <img
+                  :src="row.images[0]"
+                  alt="图片预览"
+                  class="preview-img"
+                  @click="handlePreview(row.images, 0)"
+                />
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          width="100"
+          align="center"
+          prop="categoryName"
+          label="照片分类"
+        >
+        </el-table-column>
+        <el-table-column align="center" prop="orgName" label="所属组织" />
+        <el-table-column align="center" prop="createTime" label="上传时间" />
+        <el-table-column align="center" prop="passName" label="审核状态">
+          <template #default="{ row }">
+            <span v-if="row.passName=='已通过'" style="color:#67c23a">{{ row.passName }}</span>
+            <span v-if="row.passName=='待审核'" style="color:#409eff">{{ row.passName }}</span>
+            <span v-if="row.passName=='已拒绝'" style="color:#f56c6c">{{ row.passName }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" prop="userName" label="审核人" />
+        <el-table-column align="center" prop="passTime" label="审核时间" />
+        <el-table-column align="center" label="操作" fixed="right" width="200">
+          <template #default="{ row }">
+            <el-button type="primary" @click="infoClick(row)" link
+              >详情</el-button
+            >
+            <el-button
+              type="primary"
+              v-if="row.passName == '待审核'"
+              @click="operationPassChange(row)"
+              link
+              >通过</el-button
+            >
+            <el-button
+              type="danger"
+              v-if="row.passName == '待审核'"
+              @click="operationRefuseChange(row)"
+              link
+              >拒绝</el-button
+            >
+            <!-- <el-button type="danger" @click="deleteS(row)" link>删除</el-button> -->
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页组件 -->
+      <div class="pageSize">
+        <span></span>
+        <el-pagination
+          background
+          :current-page="currentPage"
+          :page-size="pageSize"
+          :page-sizes="[10, 20, 30, 40]"
+          layout="total,sizes, prev, pager, next, jumper, slot"
+          :total="total"
+          @size-change="handleSizeChange"
+          @update:current-page="handleCurrentChange"
+        />
+      </div>
+    </div>
+  </div>
+  <!-- 添加账号弹窗 -->
+  <el-dialog
+    class="addStaff"
+    v-model="addDialogVisible"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    :title="dialongTitle"
+    align-center
+    width="540"
+    :before-close="cancelAdd"
+    destroy-on-close
+    draggable
+  >
+    <el-form
+      ref="ruleFormRef"
+      :model="ruleForm"
+      :rules="rules"
+      label-width="80px"
+      class="demo-ruleForm"
+      :size="formSize"
+      label-position="right"
+      status-icon
+    >
+      <el-form-item
+        label="审批意见 :"
+        :prop="dialongTitle == '拒绝审批' ? 'passValue' : ''"
+      >
+        <el-input
+          v-model.trim="ruleForm.passValue"
+          placeholder="请输入审批意见"
+          clearable
+          :autosize="{ minRows: 4 }"
+          type="textarea"
+        />
+      </el-form-item>
+      <el-form-item class="options">
+        <el-button @click="cancelAdd">取消</el-button>
+        <el-button
+          color="rgba(0, 97, 255, 1)"
+          class="queding"
+          type="primary"
+          @click="submitAdd(ruleFormRef)"
+        >
+          确定
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </el-dialog>
+  <!-- 详情 -->
+  <el-dialog
+    class="projectImport"
+    v-model="infoVisible"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    title="详情"
+    align-center
+    width="600"
+    :before-close="cancelInfo"
+    draggable
+  >
+    <div style="margin-bottom: 15px">
+      <el-descriptions :column="1">
+        <el-descriptions-item label="申请人 :">{{
+          infoData.userName
+        }}</el-descriptions-item>
+        <el-descriptions-item label="联系电话 :">{{
+          infoData.phone
+        }}</el-descriptions-item>
+        <el-descriptions-item label="照片 :">
+          <div class="img-preview-list" v-if="infoData.images">
+            <div
+              class="img-item"
+              style="width: 60px; height: 60px; margin: 10px 0"
+              v-for="(url, index) in infoData.images"
+              :key="index"
+            >
+              <img
+                :src="url"
+                alt="图片预览"
+                class="preview-img"
+                @click="handlePreview(infoData.images, index)"
+              />
+            </div>
+          </div>
+        </el-descriptions-item>
+        <el-descriptions-item label="照片分类 :">{{
+          infoData.categoryName
+        }}</el-descriptions-item>
+        <el-descriptions-item label="所属组织 :">{{
+          infoData.orgName
+        }}</el-descriptions-item>
+        <el-descriptions-item label="上传时间 :">{{
+          infoData.createTime
+        }}</el-descriptions-item>
+        <el-descriptions-item label="审核状态 :">{{
+          infoData.passName
+        }}</el-descriptions-item>
+        <el-descriptions-item label="审核人 :">{{
+          infoData.adminName
+        }}</el-descriptions-item>
+        <el-descriptions-item label="审核时间 :">{{
+          infoData.passTime
+        }}</el-descriptions-item>
+      </el-descriptions>
+    </div>
+  </el-dialog>
+</template>
+
+<script setup>
+import {
+  ref,
+  watch,
+  reactive,
+  nextTick,
+  onBeforeMount,
+  onUnmounted,
+} from "vue";
+import { useRouter } from "vue-router";
+import { genFileId, ElMessage, ElMessageBox } from "element-plus";
+import { dayjs } from "element-plus";
+import lodash from "lodash";
+
+import { storeToRefs } from "pinia";
+import { useCounterStore } from "@/stores/index";
+import { api as viewerApi } from "v-viewer";
+import {
+  getQueryImageApplyPage,
+  toExamineImage,
+  queryCategoryImages,
+} from "@/api/alumni-album.js";
+
+const router = useRouter();
+const store = useCounterStore();
+
+// 为避免解构时失去响应性
+const { name, age, isCollapse, realAge, collegeRole } = storeToRefs(store);
+
+// 表格数据
+const loading = ref(false);
+const tableData = reactive({
+  list: [{}],
+});
+const dialongTitle = ref("新增账号"); // 弹窗标题
+
+const searchInput = reactive({
+  userName: "",
+  categoryId: null,
+  isPass: null,
+  createTime: null,
+}); // 搜索按钮数据
+
+const currentPage = ref(1); // 当前页
+const pageSize = ref(10);
+const total = ref(0); // 当前总数
+const selectIds = ref([]); // 勾选的全部数据
+
+const addDialogVisible = ref(false); // 控制添加账号弹窗
+const categoryData = ref();
+
+// 表单数据
+const formSize = ref("default");
+const ruleFormRef = ref();
+const ruleForm = reactive({
+  passValue: "",
+  id: "",
+});
+// 表单验证
+const rules = reactive({
+  passValue: [{ required: true, message: "审批意见不能为空", trigger: "blur" }],
+});
+
+const infoVisible = ref(false);
+const infoData = ref({});
+
+// 获取账户列表
+const getList = async () => {
+  loading.value = true;
+  let params = {
+    currentPage: currentPage.value, // 当前页
+    pageCount: pageSize.value, // 一页数据条数
+    categoryId: searchInput.categoryId,
+    userName: searchInput.userName,
+    isPass: searchInput.isPass,
+  };
+  if (searchInput.createTime) {
+    params.startTime = searchInput.createTime[0];
+    params.endTime = searchInput.createTime[1];
+  }
+  getQueryImageApplyPage(params).then((res) => {
+    console.log(res, "照片上传审核分页数据");
+    if (res.code == 200) {
+      tableData.list = res.data.list;
+      total.value = res.data.totalCount;
+      loading.value = false;
+    } else {
+      loading.value = false;
+    }
+  });
+};
+
+// 搜索功能
+const searchBtn = lodash.debounce(async () => {
+  currentPage.value = 1;
+  getList();
+}, 300);
+const resetBtn = lodash.debounce(async () => {
+  searchInput.categoryId = "";
+  searchInput.userName = "";
+  searchInput.createTime = null;
+  searchInput.isPass = null;
+  currentPage.value = 1;
+  getList();
+}, 300);
+
+const handlePreview = (images, index) => {
+  // 核心:复制数组,把点击的图片移到第一位
+  const newImages = [...images]; // 拷贝原数组,避免修改原数据
+  const currentImg = newImages.splice(index, 1)[0]; // 取出当前点击的图片
+  newImages.unshift(currentImg); // 放到数组开头
+
+  // 传给预览器,此时插件显示的第一张就是点击的图片
+  viewerApi({
+    images: newImages,
+    zIndex: 3000,
+  });
+};
+
+const deleteS = async (row) => {
+  ElMessageBox.confirm("是否删除此数据?", "提示!!!", {
+    confirmButtonText: "确认",
+    cancelButtonText: "取消",
+    type: "warning",
+  })
+    .then(async () => {
+      let params = {
+        id: row.id,
+      };
+      let res = await deleteCategoryImage(params);
+      if (res.code == 200) {
+        getList();
+        ElMessage({
+          type: "success",
+          showClose: true,
+          message: res.message,
+          center: true,
+        });
+      } else {
+        ElMessage({
+          type: "error",
+          showClose: true,
+          message: res.message,
+          center: true,
+        });
+      }
+    })
+    .catch(() => {
+      loading.value = false;
+    });
+};
+// 通过
+const operationPassChange = async (row) => {
+  dialongTitle.value = "通过审批";
+  addDialogVisible.value = true;
+  ruleForm.passValue = null;
+  ruleForm.id = row.id;
+};
+// 拒绝
+const operationRefuseChange = async (row) => {
+  dialongTitle.value = "拒绝审批";
+  addDialogVisible.value = true;
+  ruleForm.passValue = null;
+  ruleForm.id = row.id;
+};
+
+// 确认添加员工
+const submitAdd = lodash.debounce(async (formEl) => {
+  if (!formEl) return;
+  await formEl.validate(async (valid, fields) => {
+    if (valid) {
+      let data = {
+        id: ruleForm.id,
+        isPass: dialongTitle.value == "通过审批" ? 2 : 3,
+        passValue: ruleForm.passValue,
+      };
+      let res = await toExamineImage(data);
+      if (res.code == 200) {
+        addDialogVisible.value = false;
+        ElMessage({
+          type: "success",
+          showClose: true,
+          message: res.message,
+          center: true,
+        });
+        getList();
+      } else {
+        ElMessage({
+          type: "error",
+          showClose: true,
+          message: res.message,
+          center: true,
+        });
+      }
+    } else {
+      console.log("error submit!", fields);
+    }
+  });
+}, 1000);
+
+const cancelAdd = () => {
+  addDialogVisible.value = false;
+};
+
+// 多选框功能
+const handleSelectionChange = (val) => {
+  // console.log(val);
+  selectIds.value = val.map((i) => i.id);
+  console.log(selectIds.value);
+};
+
+// 表格斑马纹颜色修改
+const tableRowClassName = ({ row, rowIndex }) => {
+  if (rowIndex % 2 === 0) {
+    return "even";
+  } else if (rowIndex % 2 !== 0) {
+    return "odd";
+  }
+  return "";
+};
+// 每页显示条数
+const handleSizeChange = (value) => {
+  console.log(value, "每页显示条数");
+  pageSize.value = value;
+};
+// 分页
+const handleCurrentChange = (value) => {
+  // console.log(value);
+  currentPage.value = value;
+};
+
+const infoClick = (row) => {
+  console.log(row);
+
+  infoVisible.value = true;
+  infoData.value = row;
+};
+
+const cancelInfo = () => {
+  infoVisible.value = false;
+};
+
+const categoryList = async () => {
+  let res = await queryCategoryImages();
+  // console.log(res, "相册分类下拉列表数据");
+  if (res.code == 200) {
+    categoryData.value = res.data;
+  } else {
+    ElMessage({
+      type: "error",
+      showClose: true,
+      message: res.message,
+      center: true,
+    });
+  }
+};
+
+onBeforeMount(() => {
+  categoryList();
+  getList();
+});
+onUnmounted(() => {
+  // document.removeEventListener("keyup", Enters);
+});
+</script>
+
+<style scoped lang="scss">
+.scroll {
+  width: calc(100% - 60px);
+  height: calc(100% - 61px);
+  margin: 0 auto;
+  display: flex;
+  flex-direction: column;
+
+  .middle {
+    width: calc(100%);
+    color: #000;
+    .filter {
+      display: flex;
+      flex-wrap: wrap;
+      align-items: center;
+      .search {
+        margin-left: 0 !important;
+        color: #fff;
+      }
+      .condition {
+        display: flex;
+        align-items: center;
+        margin: 10px 30px 10px 0;
+        :deep(.el-input .el-input__inner) {
+          font-size: 14px;
+        }
+        .el-select {
+          width: 220px;
+        }
+        span {
+          margin: 0 10px 0 0;
+        }
+      }
+    }
+    .gongneng {
+      margin: 10px 0;
+      .el-button {
+        color: #fff;
+        margin-right: 15px;
+      }
+    }
+  }
+  .footer {
+    width: calc(100%);
+    flex: 1;
+    margin: 0 auto;
+    overflow: auto;
+
+    .el-table--fit {
+      height: calc(100% - 60px);
+      :deep(.el-table__header-wrapper) {
+        background-color: #000;
+        font-size: 15px;
+        color: #000;
+        .cell {
+          color: #000;
+        }
+      }
+      :deep(.el-table__row) {
+        height: 50px;
+        font-size: 15px;
+        color: #000;
+      }
+      :deep(.el-table__row td) {
+        padding: 0;
+        border: 0;
+      }
+
+      .el-button--primary {
+        margin-left: 5px;
+      }
+      :deep(.el-table__body .even) {
+        background-color: #fff;
+      }
+      :deep(.el-table__body .odd) {
+        background-color: rgba(240, 243, 247, 1);
+      }
+    }
+
+    .pageSize {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin: 0 30px;
+      height: 60px;
+
+      span {
+        color: #000;
+      }
+
+      .el-pagination {
+        // width: 1600px;
+        :deep(.el-pagination__total) {
+          color: #000;
+        }
+
+        :deep(.el-pagination__goto) {
+          color: #000;
+        }
+
+        :deep(.el-pagination__classifier) {
+          color: #000;
+        }
+
+        :deep(.el-input__wrapper) {
+          border: 1px solid rgba(0, 0, 0, 1);
+          border-radius: 5px;
+          box-shadow: none;
+        }
+
+        :deep(.el-pager li) {
+          margin: 0 5px;
+          border: 1px solid rgba(0, 0, 0, 1);
+          border-radius: 5px;
+          background-color: transparent;
+        }
+
+        :deep(.el-pager li.is-active) {
+          // background-color: rgba(0, 97, 255, 0.8);
+          border: 1px solid rgba(0, 97, 255, 1);
+          color: rgba(0, 97, 255, 1);
+        }
+
+        :deep(.btn-prev) {
+          margin-right: 5px;
+          border: 1px solid rgba(0, 0, 0, 1);
+          border-radius: 5px;
+          background-color: transparent;
+        }
+
+        :deep(.btn-next) {
+          margin-left: 5px;
+          border: 1px solid rgba(0, 0, 0, 1);
+          border-radius: 5px;
+          background-color: transparent;
+        }
+      }
+    }
+  }
+}
+
+// 添加员工弹窗样式
+.addStaff {
+  .el-dialog__body {
+    .options {
+      margin: 20px 0;
+      display: flex;
+      flex-direction: row-reverse;
+      .queding {
+        margin-left: 20px;
+        background: linear-gradient(
+          90deg,
+          rgba(38, 151, 255, 1) 0%,
+          rgba(102, 181, 255, 1) 100%
+        );
+        border: none;
+      }
+      .quxiao {
+        border: 1px solid rgba(43, 151, 252, 1);
+        color: rgba(43, 151, 252, 1);
+      }
+    }
+  }
+}
+</style>

+ 0 - 0
src/views/alumni-album/PhotoCategory.vue


Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov