Node+Vue实现高校公寓管理系统设计与开发

作者主页:编程千纸鹤

作者简介:Java、前端、Pythone开发多年,做过高程,项目经理,架构师

主要内容:Java项目开发、毕业设计开发、面试技术整理、最新技术分享

一,项目简介

目前整个社会经济和生活,都严重依赖于互联网,如果没有了互联网和信息化技术的应用,市场可能会一蹶不振,严重影响经济的发展水平,影响人们的生活质量。计算机的发展,不管是从硬件还是软件,都有很多技术储备,每年都有很多的技术和软件产生,纵观各个领域,无一不用互联网软件,办公用的还是电脑居多,但是人手一台智能设备已经变成了现在人们的生活日常,哪怕的普通的老百姓都成了上知天文下知地理的所在,这些都依赖于互联网技术。互联网技术在信息的传播方面是巨大的,而信息的处理就变成了各种产业管理者和维护者的重任。人们已经习惯了互联网的存在,所以经常操作一些互联网产品变成了日常,所以开发一个高校公寓管理系统,让人们使用是没有一点问题的,并且在这个过程中不仅能够规范高校公寓信息管理的使用流程还有信息处理流程,也能让整个信息的传播处理,都存在一种可控制的范围。

当开发软件变成了一个潮流之后,会发现不管任何行业都能开发适合自己的软件,不管是内部员工管理,还是财务管理,甚至业务管理都可以数据化,并且可以对这些数据集中处理,进而根据数据处理结果就自然而然的提高了管理水平,最重要的是,开发一个软件投入使用,开发过程其实就是梳理行业痛点的过程,就是让软件来弥补行业的管理漏洞,不断的优化事物的处理流程。学生公寓管理系统就是一款专门开发的软件,通过Web技术,让使用者可以在任何一台智能设备上面通过浏览器进行操作使用,对数据的处理不在局限于地域距离,只要软件开发到位,使用起来方便,达到预期目的,会发现有软件和没有软件的区别是很大的,有了这款软件之后,会发现数据的存储安全方面,比起之前的满屋寻找记录的优势是多么的巨大。

 本系统以VSCODE为开发工具,运用mongodb数据库技术,开发了一个学生公寓管理系统。此系统实现的功能具体如下:
   1.用户登录功能:用户通过登入界面输入用户名称和登录密码,经过身份验证模块识别用户的合法性,然后查询相关信息。用户身份主要有系统管理员和学生两个,不同的身份进入系统所操作的功能模块不同。

   2.水电管理功能:该功能可以查收公寓的水电费缴纳情况,提醒学生交费,并实现在线充值功能,通过支付宝沙箱实现在交缴费功能。
   3.公寓住宿人员管理功能:主要对公寓住宿人员进行信息的管理操作,主要包含公寓人员新增、查询、修改和删除操作。
   4.安全设施管理功能:主要对公寓配套的像消防器材等安全管理的设施信息进行基本的管理功能。
   5.外来访客管理功能:主要对外来到访人员进行信息登记,以备查询使用。

   6.宿舍报修管理:学生可以登陆系统进行报修,管理员在后台对报修的信息进行管理,可以根据维修情况修改报修的状态。

   7.宿舍楼管理功能:主要对宿舍楼信息进行管理,并指派宿舍管理人员。

   8.宿舍管理:主要对宿舍住宿情况进行管理,可以为宿舍添加住宿人员等,并指定宿舍长。 

二,环境介绍

语言环境:NODEJS

数据库:mon

应用服务器:NODEJS

开发工具:VSCODE或IDEA

vue3+elementplus+vite+koa2+MongoDB

三,系统展示

5.1  系统的实现平台

学生公寓管理系统在系统从属性应该属于学校内部信息化建设平台的一个组成部分,其中涉及到的用户信息也可以来源于学校内部信息化平台,也可以独立作为一个用户体系。目前我们所设计的用户是独立设计的,可以通地我们提供页面登陆窗口登录,登陆后即可根据不同身份来操作学生公寓管理系统中的不同业务模块。系统所使用的数据库应该与校内信息化平台的后台数据库的相关数据保持同步,当信息平台的用户信息修改后,应该可以借助第三方组件比消息通信组件RabbmitMQ或Cancal等组将信息同步到本系统数据库。

    本部分主要介绍一下系统运行的环境要求,以及具体实现的相关功能模块实现的功能介绍及UI界面展示。

5.2  管理员功能模块的实现

    学生公寓管理系统登陆界面。系统分为二类用户,分别是管理员、学生,用户登陆时选择自己账户对应的身份,提交信息到后台验证,验证通过后即可实现和目前身份匹配的相关功能模块的使用。为了安全起见,本登陆操作增加了图形验证码,通过验证码可以防止恶意登陆,验证码校验通过后,才会校验账户信息。

图5.1 学生公寓管理系统主界面

5.2.1  系统管理主页

    本次所设计的学生公寓管理系统,为方便对学生、宿舍、水电费等的相关统计,直观的了解目前学校各宿舍的相关的业务数据。具体展示效果如下图5.2所示:

图5.2 管理首页主界面

5.2.2  水电费管理模块

学生公寓管理系统中水电费管理模块的实现,它的基本功能是查询管理各宿舍所使用的水电费的信息,并实现在线缴费的功能。首先查询到各宿舍目前水电费充值情况,然后提醒宿舍进行及时充值。具体展示如下图5.3、图5.4所示:

图5.3 电费信息管理主界面

图5.4 水费信息管理界面

5.2.3  宿舍人员信息模块

学生公寓管理系统中对于在校公寓住宿人员信息管理功能的实现,主要管理本校在校公寓住宿人员的相关信息。首先查询到所有在校住宿的学员,将其信息查询并以分页形式在前端页面进行展示,并且能对住宿学生的人信息进行添加、搜索等管理操作。具体展示如下图5.5所示:

图5.5 住宿人员管理界面

5.2.4  安全设施信息管理模块

学生公寓管理系统中安全设施信息管理模块的实现,它的基本功能是查询管理修改宿舍楼中配置的安全设施信息。首先查询到所有安全配置设施信息以分页形式进行展示,并且能对安全设施信息进行添加查询等管理。具体展示如下图5.6所示:

图5.6 安全设施信息管理界面

5.2.5 访客信息管理模块

学生公寓管理系统中来访人员信息管理模块的实现,它的基本功能是查询管理修改外来人员的到访信息。首先查询到所有到访问登记信息以分页形式进行展示,并且能对到访信息进行相关管理。具体展示如下图5.7所示:

图5.7 访客信息管理界面

5.2.6  报修信息模块

学生公寓管理系统中报修信息管理模块的实现,它的基本功能是查询管理修改各宿舍上报的报修信息。首先查询到所有报修信息以分页形式进行展示,并且能对报修信息进行修改删除等管理。根据维修情况来修改报修的维修状态,并根据是否人为损坏来确定宿舍人员支付的维修金额。具体展示如下图5.8、5.9所示:

图5.8 报修信息管理界面

图5.9 报修状态修改界面

5.2.7  宿舍楼管理信息模块

学生公寓管理系统中对各学生住宿的宿舍楼管理模块的实现,它的基本功能是查询管理各宿舍楼的基本信息。首先查询到所有宿舍楼信息以分页形式进行展示,并且能对各宿舍楼信息进行添加、修改和删除等管理。具体展示如下图5.10、5.11所示:

图5.10宿舍楼管理界面

图5.11宿舍楼添加界面

5.2.8  宿舍信息模块

在本次开发设计的学生公寓管理系统中,对学生公寓信息进行相关管理的实现,它的基本功能是查询管理修改宿舍的基本信息。首先查询到所有宿舍信息以分页形式进行展示,并且能对宿舍信息进行增加、修改、删除和搜索等管理。具体展示如下图5.12所示:

图5.12 宿舍信息管理界面

四,核心代码展示

const buildModel = require('../../models/build')
const getAllBuildList = async ctx => {
  await buildModel.find({}).then((res) => {
    ctx.body = { code: 200, msg: "查询所有楼宇成功", data: res }
  })
}
const addBuild = async ctx => {
  const addData = ctx.request.body
  await buildModel.create(addData).then(() => {
    ctx.body = { code: 200, msg: "添加新楼宇成功", result: true }
  }).catch(() => {
    ctx.body = { code: 400, msg: "添加新楼宇失败", result: false }
  })
}
const removeBuild = async ctx => {
  const removeData = ctx.request.body
  console.log(removeData)
  await buildModel.findOneAndRemove(removeData).then(() => {
    ctx.body = { code: 200, msg: "删除楼宇成功", result: true }
  }).catch(() => {
    ctx.body = { code: 200, msg: "删除楼宇成功", result: false }
  })
}
module.exports = {
  getAllBuildList,
  addBuild,
  removeBuild
} 

const dormModel = require('../../models/dorm')
const studentModel = require('../../models/student')
const addDorm = async ctx => {
  const addData = ctx.request.body
  await dormModel.findOne({ code: addData.code }).then(async (res) => {
    if (res && res.belongTo === addData.belongTo) {
      ctx.body = { code: 200, msg: '该宿舍已存在', result: false }
    }
    else {
      await dormModel.create(addData).then(() => {
        ctx.body = { code: 200, msg: '新增宿舍成功', result: true }
      })
    }
  })
}
const getAllDormList = async ctx => {
  await dormModel.find({}).then(async (res) => {
    ctx.body = { code: 200, msg: "获取所有寝室信息成功", data: res }
  })
}
const getDormPersonnel = async ctx => {
  const { userIdList } = ctx.request.body
  const result = []
  return new Promise((resolve, reject) => {
    userIdList.forEach(async (user_id, index) => {
      await studentModel.find({ user_id }).then((res) => {
        result.push(res[0])
      })
      if (index === userIdList.length - 1) {
        resolve()
      }
    })
  }).then(() => {
    return ctx.body = { code: 200, msg: '获取寝室成员信息成功', data: result }
  })
}
const addUserToDorm = async ctx => {
  const addData = ctx.request.body
  await dormModel.findById({ _id: addData.toDormId }).then(async (res) => {
    await dormModel.updateOne({ _id: addData.toDormId }, { personnel: [...res.personnel, ...addData.addUserId] }).then(async () => {
      await studentModel.findOneAndUpdate({ user_id: addData.addUserId }, { dorm: res.code, building: res.belongTo }).then(() => {
        console.log(res)
        ctx.body = { code: 200, msg: '添加学生至宿舍成功', result: true }
      })
    })
  })
}
const removeUserToDorm = async ctx => {
  const removeData = ctx.request.body
  await dormModel.findById({ _id: removeData.dormId }).then(async (res) => {
    const personnel = res.personnel
    const removeIndex = res.personnel.indexOf(removeData.userId)
    personnel.splice(removeIndex, 1)
    await dormModel.updateOne({ _id: removeData.dormId }, { personnel: res.personnel }).then(async () => {
      await studentModel.findOneAndUpdate({ user_id: removeData.userId }, { dorm: '无', building: '无' }).then(() => {
        ctx.body = { code: 200, msg: '该学生从宿舍中删除成功', result: true }
      })
    })
  })
}
const deleteDorm = async ctx => {
  const deleteData = ctx.request.body
  var personnel = []
  await dormModel.findOne({ code: deleteData.code, belongTo: deleteData.belongTo }).then(async (res) => {
    personnel = res.personnel
    await dormModel.deleteOne({ code: deleteData.code, belongTo: deleteData.belongTo }).then(() => {
      return new Promise((resolve, reject) =>
        personnel.forEach(async (user_id, index) => {
          await studentModel.findOneAndUpdate({ user_id }, { dorm: '无', building: '无' })
          if (index === personnel.length - 1) {
            resolve()
          }
        })).then(() => {
          ctx.body = { code: 200, msg: "删除宿舍成功", result: true }
        })
    })
  })
}
const changeDormAdmin = async ctx => {
  const changeData = ctx.request.body
  await dormModel.findByIdAndUpdate({ _id: changeData._id }, { admin: changeData.admin }).then(() => {
    ctx.body = { code: 200, msg: "修改寝室长成功", result: true }
  })
}
const getDormByBuild = async ctx => {
  const building = ctx.query.building
  console.log(building)
  await dormModel.find({ belongTo: building }).then((res) => {
    ctx.body = { code: 200, msg: '获取楼宇对应宿舍成功', data: res }
  })
}
module.exports = {
  addDorm,
  getAllDormList,
  getDormPersonnel,
  addUserToDorm,
  removeUserToDorm,
  deleteDorm,
  changeDormAdmin,
  getDormByBuild
}
const facilitiesModel = require('../../models/facilities')
const handleTime = require('../../../tools/O').timeHandler
const addFacilitiesInspectTerm = async ctx => {
  addData = ctx.request.body
  addData.inspectTime = handleTime()
  await facilitiesModel.create(addData).then(() => {
    ctx.body = { code: 200, msg: "添加检查设施信息成功", result: true }
  }).catch(() => {
    ctx.body = { code: 400, msg: "添加检查设施信息失败", result: false }
  })
}
const getFacilitiesInepectData = async ctx => {
  await facilitiesModel.find({}).then((res) => {
    ctx.body = { code: 200, msg: "获取公寓检查设施表成功", data: res }
  })
}

module.exports = {
  addFacilitiesInspectTerm,
  getFacilitiesInepectData
}
const repairModel = require('../../models/repair')
const getAllRepairFormList = async ctx => {
  await repairModel.find().then((res) => {
    ctx.body = { code: 200, msg: "获取用户报修单成功", data: res }
  })
}
const deleteRepair = async ctx => {
  const deleteData = ctx.request.body
  await repairModel.findOneAndDelete({ deleteData }).then(() => {
    ctx.body = { code: 200, msg: "删除保修单成功", result: true }
  })
}
const changeRepairState = async ctx => {
  const changeData = ctx.request.body
  await repairModel.findByIdAndUpdate({ _id: changeData._id }, changeData).then(async () => {
    ctx.body = { code: 200, msg: "改变保修单状态成功", result: true }
  }).catch(err => {
    console.log(err)
    ctx.body = { code: 200, msg: "改变保修单状态失败", result: false }
  })
}
module.exports = {
  getAllRepairFormList,
  deleteRepair,
  changeRepairState
} 

前端页面

<template>
  <div class="build">
    <div class="build-list">
      <div class="title">
        <div class="left-title">
          <p>公寓楼宇表</p>
          <el-button type="primary" @click="activeAddUserCheckBoxEvent"
            >添加</el-button
          >
          <el-button type="primary" @click="refreshBuildListEvent"
            >刷新</el-button
          >
        </div>
        <el-input
          class="search-input"
          type="text"
          :suffix-icon="Search"
          placeholder="请输入你要搜索的内容"
          v-model="data.buildSearchKeyWord"
          @input="searchRepairListEvent"
        ></el-input>
      </div>
      <el-table stripe border :data="VuexData.allBuildList" style="width: 100%">
        <el-table-column
          property="name"
          label="楼宇名称"
          show-overflow-tooltip
          width="120"
        />
        <el-table-column
          property="admin"
          label="负责人"
          show-overflow-tooltip
          width="200"
        />
        <el-table-column
          property="sex"
          label="性别"
          show-overflow-tooltip
          width="200"
        />
        <el-table-column property="phonenumber" label="联系电话" />
        <el-table-column width="120" fixed="right" label="操作">
          <template #default="scope">
            <el-button
              type="primary"
              size="small"
              @click="deleteBuildEvent(scope.row)"
              >删除</el-button
            >
          </template>
        </el-table-column>
      </el-table>
    </div>
    <el-dialog v-model="data.activeAddBuild" title="添加楼宇" width="40%">
      <el-form
        ref="ruleFormRef"
        :model="ruleForm"
        status-icon
        :rules="rules"
        label-width="120px"
        class="demo-ruleForm"
      >
        <el-form-item label="楼宇名" prop="name">
          <el-input
            v-model="ruleForm.name"
            type="text"
            placeholder="请输入楼宇名"
            autocomplete="off"
          />
        </el-form-item>
        <el-form-item label="楼宇管理员:" prop="admin">
          <el-input
            v-model="ruleForm.admin"
            type="text"
            placeholder="请输入楼宇管理员名字"
            autocomplete="off"
          />
        </el-form-item>
        <el-form-item label="管理员性别" placeholder="请选择性别" prop="sex">
          <el-select
            v-model="ruleForm.sex"
            class="m-2"
            placeholder="管理员性别"
            prop="sex"
          >
            <el-option
              v-for="i in ['男', '女']"
              :key="i"
              :label="i"
              :value="i"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="管理员手机号" prop="phonenumber">
          <el-input
            v-model="ruleForm.phonenumber"
            type="text"
            placeholder="请输入管理员手机号"
            autocomplete="off"
          />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="postBuildData">提交</el-button>
          <el-button @click="resetForm(ruleFormRef)">重置</el-button>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="data.activeAddBuild = false">关闭</el-button>
          <el-button type="primary" @click="postBuildData">提交</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script lang="ts" setup>
import { Search } from "@element-plus/icons-vue";
import message from "element-plus/es/components/message";
import { reactive, ref, onMounted } from "vue";
import { ElMessage, ElTable, ElMessageBox } from "element-plus";
import { useStore } from "vuex";
import O from "../../tools/O";
import type { FormInstance } from "element-plus";
interface User {
  date: string;
  name: string;
  address: string;
}
const store = useStore();
const multipleTableRef = ref<InstanceType<typeof ElTable>>();
const multipleSelection = ref<User[]>([]);
const VuexData = reactive({
  allBuildList: store.state.vx_admin.allBuildList,
});
const refreshBuildListEvent = () => {
  VuexData.allBuildList = store.state.vx_admin.allBuildList;
  ElMessage({
    message: "刷新成功",
    type: "success",
  });
};
const data = reactive({
  buildSearchKeyWord: ref(""),
  activeAddBuild: ref(false),
});
const activeAddUserCheckBoxEvent = () => {
  data.activeAddBuild = true;
};
const searchRepairListEvent = () => {
  if (data.buildSearchKeyWord.trim() === "") {
    return (VuexData.allBuildList = store.state.vx_admin.allBuildList);
  }
  VuexData.allBuildList = VuexData.allBuildList.filter((repair) => {
    return (
      repair.name.includes(data.buildSearchKeyWord) ||
      repair.sex.includes(data.buildSearchKeyWord) ||
      repair.admin.includes(data.buildSearchKeyWord) ||
      repair.phonenumber.includes(data.buildSearchKeyWord)
    );
  });
};
const ruleFormRef = ref<FormInstance>();

const checkAddInspectData = (rule: any, value: any, callback: any) => {
  if (!value) {
    return callback(new Error("该项不能为空"));
  }
  callback();
};

const ruleForm = reactive({
  name: "",
  sex: "",
  phonenumber: "",
  admin: "",
});

const rules = reactive({
  name: [{ validator: checkAddInspectData, trigger: "blur" }],
  sex: [{ validator: checkAddInspectData, trigger: "blur" }],
  phonenumber: [{ validator: checkAddInspectData, trigger: "blur" }],
  admin: [{ validator: checkAddInspectData, trigger: "blur" }],
});

const resetForm = (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  formEl.resetFields();
};
const postBuildData = () => {
  store.dispatch("vx_admin/addBuild", ruleForm).then((res) => {
    ElMessage({
      message: res.msg,
      type: res.result ? "success" : "error",
    });
    data.activeAddBuild = false;
    VuexData.allBuildList = store.state.vx_admin.allBuildList;
  });
};
const deleteBuildEvent = (removeData: Object) => {
  store.dispatch("vx_admin/deleteBuild", removeData).then((res) => {
    ElMessage({
      message: res.msg,
      type: res.result ? "success" : "error",
    });
    VuexData.allBuildList = store.state.vx_admin.allBuildList;
  });
};
onMounted(async () => {
  await store.dispatch("vx_admin/getAllBuildList").then((res) => {
    VuexData.allBuildList = res.data;
  });
});
</script>

<style lang='scss' scoped>
.build {
  width: 90%;
  margin: 0 auto;
  margin-top: 50px;
  box-shadow: 0 0 10px 5px #e8e8e8;
  border-radius: 20px;
  .title {
    display: flex;
    justify-content: space-between;
    align-items: center;
    .left-title {
      display: flex;
      justify-content: flex-start;
      align-items: center;
    }
    button {
      margin-left: 20px;
    }
    .search-input {
      width: 300px;
    }
  }
  .build-list {
    padding: 20px;
    > div:not(:first-child) {
      margin-top: 40px;
    }
    .title {
      font-size: 18px;
    }
    .pay-electric-box {
      margin-top: 20px;
      display: flex;
      justify-content: flex-start;
      align-items: center;
      > div:not(:first-child) {
        margin-left: 20px;
      }
      .floor {
        color: #000;
        font-size: 16px;
      }
      .electric-surplus {
        color: #d63031;
      }
      .used-electric {
        color: #b2bec3;
      }
    }
    .pay-history {
      .title {
        display: flex;
        justify-content: flex-start;
        align-items: center;
        button {
          margin-left: 20px;
        }
      }
      .history-box {
        margin-top: 20px;
      }
    }
  }
}
</style>

五,项目总结

数据库设计

从需求分析可以看出,本系统存在以下几个实体:

管理员实体:主要存储管理员登陆的账户和密码

宿舍类实体:主要存储宿舍楼名称、管理员、性别、电话号码

访客登记实体:用于存储来访人、来访时间、登记管理员、来访宿舍等。

宿舍实体:用于存储宿舍编号、管理员、人员信息(集合)、人员详情信息(集合)、水电费信息等。

水电费支付记录实体:用于支付人、类型、金额、时间等。

报修实体:用于存储报修类型、时间、人员、位置、问题及描述等。

维修实体:用于存储维修设施的名字、所属宿舍类、宿舍编号、金额、损坏原因等。

学生实体:用于存储学生姓名、姓别、编号、专业、班级、所属宿舍、密码 、宿舍楼、学号等。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程千纸鹤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值