本文介绍: 这是一个适合初学Vue3的小白(比如本人,自学小白,目前大二,过完暑假就大三了,想要做一个项目复习一些所学的内容)做的小型项目,项目是后台管理系统。所用涉及到的技术栈为Vue3、Vuecli、Vuerouter、Vuexelementuiechartsaxiosmysqlnode.js**其中echartsaxiosmysqlnode.js只是简单使用,不涉及复杂操作elementui里面表单等,也没有进行相关检验,总体功能只是想让初学者有有一个项目体验,或多或少美中不足。.

前言

Vue项目代码

初始化项目

  1. vue create 项目名称(比如shop)
  2. 我们手动配置选择***Manually select features***
  3. 选择Babel(默认自动选择) Roter Vuex CSS-processors 空格可以选择或者取消选择配置,此处我们不要选择Linter / Formatter
  4. 选择3.×
  5. Use history mode for router 选择 n
  6. Pick a CSS preprocessor 选择less
  7. Where do you prefer placing config for Babel, ESLint, etc.? 选择In dedicated config files
  8. Save this as a preset for future projects? 选择N
  9. 启动项目 进入创建目录(比如shop)中 npm run serve
vue create 项目名称

下载相关包

//安装element-plus
npm install element-plus --save
//axios
npm install axios --save
// 安装vuex
npm install axios --save
// 安装echarts
npm install echarts --save

初始化组件

首先将views目录下的About.vue文件以及HomeView.vue文件components目录下的HelloWorld.vue文件删除然后清除App.vue文件里面代码放置如下代码

App.vue

App.vue代码

//App.vue
<template>
 <div>
 &lt;router-view&gt;</router-view&gt;
 </div&gt;
</template&gt;

<script>

</script>
<style lang="less">
* {
  margin: 0;
  padding: 0;
}
</style>

components目录新建一个Layout的vue文件,即Layout.vue。

Layout进行页面整体布局利用Element Plus (element-plus.org)的Container布局容器以及Menu菜单。当用户点击退出时,会清除掉token用户需要重新登录为什么要在Layout.vue中就拿Map.vue中的数据而不是在Map.vue中去获取 作者试过了,当我们启动这个项目时,第一次表格展示“的”echarts“(routerlink)时,展示不了图表,没有渲染上去(作者猜测,可能使用了Vuex的原因)。当我们切换到”员工管理“的”员工列表后”我们再点击表格展示“的”echarts“我们就会发现此时页面出现表格,将数据渲染到DOM上了。为了避免这种情况,我们知道Vuex就是管理数据的,Vuex能够组件使用数据,所以我们就在Layout.vue中就请求数据然后直接在Map.vue中进行使用

Layout.vue
//Layout.vue
<template>
  <div class="common-layout">
    <el-container>
      <el-header>
        <div class="header">
          <div class="header_left">
            <div class="img">
              <img src="../assets/logo.png" alt="" />
            </div>
            <div class="title">
              <div>
                <h1>最强节点人力资源管理系统</h1>
              </div>
            </div>
          </div>
          <div class="header_right">
            <el-row>
              <el-button type="primary" round @click="logOut">退出</el-button>
            </el-row>
          </div>
        </div>
      </el-header>
      <el-container>
        <el-aside width="200px">
          <el-menu
            default-active="2"
            class="el-menu-vertical-demo"
            @open="handleOpen"
            @close="handleClose"
            background-color="none"
            text-color="#fff"
            router
          >
            <el-sub-menu index="1">
              <template #title>
                <el-icon><Avatar /></el-icon>
                <span>员工管理</span>
              </template>
              <el-menu-item index="/layout/usersList">员工列表</el-menu-item>
            </el-sub-menu>
            <el-sub-menu index="2">
              <template #title>
                <el-icon><Collection /></el-icon>
                <span>表格展示</span>
              </template>
              <el-menu-item index="/layout/map">echarts</el-menu-item>
            </el-sub-menu>
          </el-menu>
        </el-aside>
        <el-main>
          <router-view></router-view>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

<script>
import { useRouter } from "vue-router";
import { useStore } from "vuex";
export default {
  setup() {
    // 此处 直接请求Map中的数据,不然第一次直接点击Map组件,将得不到数据展示。·
    // 因此就再点击map路由前,先获取到Vuex中的数据所以,Vuex本来就是用于组件使用数据,然后我们就可以在Map组件中可以使用
    const store = useStore();
    store.dispatch("asyncGetSex");
    store.dispatch("asyncgetsalaryRate");
    store.dispatch("asyncgetpersonalSalarytotals");
    const router = useRouter();
    function logOut() {
      // 清除本地储存的token
      localStorage.removeItem("token");
      alert("退出成功");
      // 跳转登录页面
      router.push("/login");
    }
    return {
      logOut,
    };
  },
};
</script>

<style lang="less" scoped>
.el-header {
  height: 6rem;
  background-color: #242a31;
}
.el-aside {
  height: 100vh;
  background-color: #2d363f;
}
.el-header,
.el-aside {
  color: #fff;
}
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  .header_left {
    display: flex;
    .img {
      width: 20%;
      height: 30%;
      margin-right: 5rem;
      img {
        display: block;
        width: 100%;
        height: 100%;
      }
    }
  }
  .title {
    display: flex;
    justify-content: center;
    align-items: center;
  }
}
a {
  color: #fff;
  text-decoration: none;
}
.header_right {
  display: flex;
  .img {
    width: 20%;
    height: 30%;
    margin-right: 5rem;
    img {
      width: 100%;
      height: 100%;
    }
  }
}
</style>

退出效果如下

[外链图片转存失败,源站可能有防盗链机制,建议图片保存下来直接上传(img-BWxtORGi-1659418267056)(https://p6-juejin.byteimg.com/toscn-i-k3u1fbpfcp/f77210c3946f477ea92cd267dbef0ced~tplv-k3u1fbpfcp-watermark.image?)]

views目录下,新建三个vue文件,分别是Login.vue,Map.vue,Userlist.vue。

Login.vue是用于管理人员进行登录的。当管理人员登录成功后,我们生成相对应的token保存localstrage中,这样子,管理人员哪怕是刷新都不会需要进行重新登陆、token是用了jsonwebtoken这个第三方生成动态数据。

Login.vue
//Login.vue
<template>
  <div class="login-container">
    <div class="center-form">
      <el-form class="login-form">
        <el-form-item prop="userNumber" label="登录账号">
          <el-input v-model="userNumber" type="text" />
        </el-form-item>
        <el-form-item prop="password" label="登录密码">
          <el-input v-model="password" type="password" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="submit">登录</el-button>
          <el-button>忘记密码</el-button>
          <el-button>重置</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
import { reactive, toRefs, ref } from "vue";
import { login } from "@/util/api/employee.js";
import { useRouter } from "vue-router";
export default {
  setup() {
    let data = reactive({
      userNumber: "",
      password: "",
    });
    let router = useRouter();
    async function submit() {
      let res = await login("login", data.userNumber, data.password);
      console.log(router);
      console.log(res.data);
      if (res.data.status == 200) {
        alert(res.data.msg);
        localStorage.setItem("token", res.data.token);
        router.push("/");
      } else {
        localStorage.removeItem("token");
      }
    }
    return {
      ...toRefs(data),
      submit,
    };
  },
};
</script>

<style lang="less" scoped>
.login-container {
  width: 100%;
  height: 50rem;
  background-color: skyblue;
  position: relative;
  .center-form {
    position: absolute;
    top: 50%;
    left: 50%;
    padding: 1rem;
    transform: translate(-50%, -50%);
    border-radius: 0.5rem;
    background-color: aliceblue;
    .login-form {
      button {
        display: block;
        margin: 1rem;
      }
    }
  }
}
</style>
Userlist.vue

Userlist.vue是用于展示员工数据,使用Element Plus (element-plus.org)的Pagination分页组件以及Table表格组件。Userlist.vue是这个项目的核心,它展示了增删改查功能,以及对拿到的数据进行分页。笔者在这里将Element Plus一些功能删除了,进行了简化
Userlist.vue并没有使用Vuex,为什么 首先笔者想要换一种写法,就在Userlist.vue中单纯进行异步请求通过axios拿到数据。其次,数据并没有跨组件进行使用,只是单单在Userlist.vue中使用了,就没必要使用Vuex了。为什么作者要将// let showUserList = ref([]); // let dataShow = ref();注释 我们知道ref和reactive都可以对值进行操作。但是reactive只能对引用型数据操作,而ref不仅可以对基本数据类型操作,还可以对引用型数据操作。笔者两种方式都试了,因此为了传统上的使用,笔者将涉及到showUserList和dataShowref的写法代码注释了。如果大家有兴趣,不妨也可以使用。特别注意,如果大家使用ref的写法,那么需要将 el-table :data=“showData.dataShow” border style=”width: 100%”改为 el-table :data=“dataShow” border style=“width: 100%” 将 :total=”showData.showUserList.length改为:total=”showUserList.length

//Userlist.vue
<template>
  <div class="usersList-container">
    <div class="sticky">
      <el-form :inline="true" :model="formInline" class="demo-form-inline">
        <div class="left-input">
          <el-form-item label="查询员工">
            <el-input
              v-model="formInline.user"
              placeholder="请输入员工号或者员工名"
            ></el-input>
          </el-form-item>
        </div>
        <el-form-item>
          <el-button type="primary" @click="onSubmit">查询</el-button>
        </el-form-item>
        <el-form-item label="添加员工">
          <el-button type="primary" @click="dialogTableVisible">添加</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="block">
      <span class="demonstration">完整功能</span>
      <div class="tanchukuang" v-if="flag">
        <form action="" class="form">
          <div>
            <label for="">工号<input type="text" v-model="I" /> <br /></label>
          </div>
          <div>
            <label for="">姓名<input type="text" v-model="N" /> <br /></label>
          </div>
          <div>
            <label for="">电话<input type="text" v-model="P" /> <br /></label>
          </div>
          <div>
            <label for="">性别<input type="text" v-model="S" /> <br /></label>
          </div>
          <div>
            <label for="">薪资<input type="text" v-model="Sa" /> <br /></label>
          </div>
          <div>
            <label for="">职位<input type="text" v-model="Po" /> <br /></label>
          </div>
          <div class="btn-left">
            <el-button @click="noSee">取消</el-button>
            <el-button type="primary" @click="submit">提交</el-button>
          </div>
        </form>
      </div>
      <el-table :data="showData.dataShow" border style="width: 100%">
        <el-table-column fixed prop="empID" label="ID" width="150">
        </el-table-column>
        <el-table-column prop="employeeName" label="姓名" width="120">
        </el-table-column>
        <el-table-column prop="employeePhone" label="手机号" width="120">
        </el-table-column>
        <el-table-column prop="employeeSex" label="性别" width="120">
        </el-table-column>
        <el-table-column prop="employeeSalary" label="薪资" width="120">
        </el-table-column>
        <el-table-column prop="employeePosition" label="职位" width="120">
        </el-table-column>
        <el-table-column fixed="right" label="操作" width="250">
          <template #default="scope">
            <el-button>查看</el-button>
            <el-button
              type="primary"
              size="small"
              @click="handleEdit(scope.$index, scope.row)"
              >编辑</el-button
            >
            <el-button
              size="small"
              type="danger"
              @click="handleDelete(scope.$index, scope.row)"
              >删除</el-button
            >
          </template>
        </el-table-column>
      </el-table>

      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :page-sizes="[2, 4, 6, 7, 8]"
        layout="total, sizes, prev, pager, next, jumper"
        :total="showData.showUserList.length"
      >
      </el-pagination>
    </div>
    <div class="update" v-if="up_flag">
      <form action="" class="form">
        <div>
          <label for=""
            >电话<input type="text" v-model="upPhone" /> <br
          /></label>
        </div>
        <div>
          <label for=""
            >薪资<input type="text" v-model="upSalary" /> <br
          /></label>
        </div>
        <div>
          <label for=""
            >职位<input type="text" v-model="upPosition" /> <br
          /></label>
        </div>
        <div class="btn-left">
          <el-button @click="hiddenUpdate">取消</el-button>
          <el-button type="primary" @click="updateEmp">提交</el-button>
        </div>
      </form>
    </div>
  </div>
</template>

<script>
import { reactive, ref, toRefs } from "vue";
import {
  getEmployees,
  addEmployees,
  deleteEmployees,
  updateEmployees,
} from "@/util/api/employee.js";
export default {
  setup() {
    const showData = reactive({
      showUserList: [],
      dataShow: [],
    });
    // let showUserList = ref([]);
    // let dataShow = ref();
    let data = getEmployees("employee");
    data.then((res) => {
      // dataShow.value = showUserList.value = res.data;
      showData.dataShow = showData.showUserList = res.data;
    });
    let flag = ref(false);
    let person = reactive({
      I: "",
      N: "",
      P: "",
      S: "",
      Sa: "",
      Po: "",
    });
    let formInline = reactive({
      user: "",
      region: "",
    });
    let dialogTableVisible = () => {
      flag.value = true;
    };
    function submit() {
      addEmployees("add", person).then(() => {
        data = getEmployees("employee");
        data.then((res) => {
          // dataShow.value = showUserList.value = res.data;
          showData.dataShow = showData.showUserList = res.data;
          console.log(dataShow.value);
        });
        flag.value = false;
      });
    }
    // 删除员工
    function handleDelete(index, row) {
      deleteEmployees("delete", row.empID).then(() => {
        data = getEmployees("employee");
        data.then((res) => {
          // dataShow.value = showUserList.value = res.data;
          showData.dataShow = showData.showUserList = res.data;
          console.log(dataShow.value);
        });
      });
    }
    // 更新员工信息
    let up_flag = ref(false);
    function hiddenUpdate() {
      up_flag.value = false;
    }
    let getID = ref();
    let upPhone = ref();
    let upSalary = ref();
    let upPosition = ref();
    function updateEmp() {
      updateEmployees(
        "update",
        getID.value,
        upPhone.value,
        upSalary.value,
        upPosition.value
      ).then(() => {
        data = getEmployees("employee");
        data.then((res) => {
          // dataShow.value = showUserList.value = res.data;
          showData.dataShow = showData.showUserList = res.data;
          console.log(dataShow.value);
        });
        up_flag.value = false;
      });
    }
    let page_number = ref();
    const handleEdit = (index, row) => {
      up_flag.value = true;
      getID.value = row.empID;
    };
    function handleSizeChange(val) {
      console.log(`每页 ${val} 条`);
      page_number.value = val;
    }
    function handleCurrentChange(val) {
      console.log(`这是第${val}页`);
      // dataShow.value = showUserList.value.slice(
      //   (val - 1) * page_number.value,
      //   val * page_number.value
      // );
      showData.dataShow = showData.showUserList.slice(
        (val - 1) * page_number.value,
        val * page_number.value
      );
    }
    function onSubmit() {
      console.log();
      // dataShow.value = showUserList.value.filter(
      //   (i) => i.empID == formInline.user || i.employeeName == formInline.user
      // );
      showData.dataShow = showData.showUserList.filter(
        (i) => i.empID == formInline.user || i.employeeName == formInline.user
      );
      console.log(dataShow.value);
    }
    function noSee() {
      flag.value = false;
    }
    return {
      // dataShow,
      // showUserList,
      showData,
      flag,
      up_flag,
      person,
      page_number,
      formInline,
      upPhone,
      upSalary,
      upPosition,
      handleEdit,
      handleDelete,
      ...toRefs(person),
      noSee,
      onSubmit,
      submit,
      dialogTableVisible,
      handleSizeChange,
      handleCurrentChange,
      hiddenUpdate,
      updateEmp,
    };
  },
};
</script>

<style lang="less" scoped>
.usersList-container {
  display: flex;
  justify-content: center;
  position: relative;
  overflow-wrap: wrap;
}

.margin {
  margin-bottom: 5rem;
}
.el-form-item__content {
  margin-right: 5rem;
}

.tanchukuang {
  z-index: 11;
  position: fixed;
  top: 30vh;
  left: 30vh;
}

.update {
  z-index: 12;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
.form {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-content: center;
  background-color: skyblue;
  position: relative;
  div {
    padding: 1rem;
    label {
      color: #fff;
    }
    input {
      color: #000;
      font-size: 1rem;
    }
  }
  .btn-left {
    transform: translateX(30%);
  }
}
</style>
Map.vue

Map.vue完全是echarts展示的可视化图,关于echarts详细使用,请点击Apache ECharts 为什么作者这里使用echarts?作者主要是看了ehcarts相关教学,但是一直都没有使用过,正好做Vue3项目,配合node.js通过mysql拿到动态数据进行使用。此处需要注意的是,只有等待DOM渲染完毕,才能使用echarts,因此,echarts的相关操作,必须要在onMounted里面才行。关于为什么不在Map.vue中请求数据,笔者在Layout.vue中就已经详细阐述了,此处不再赘述。

//Map.vue
<script>
import * as echarts from "echarts";
import { onMounted } from "vue";
import { useStore } from "vuex";
export default {
  setup(props) {
    const store = useStore();
    onMounted(() => {
      console.log(store.state.sex_totals.man_totals);
      // 绘制图表
      var myChart1 = echarts.init(document.querySelector("#left-main"));
      myChart1.setOption({
        title: {
          text: "公司男女性别比",
          subtext: "加油一起干,都是好伙伴",
          left: "center",
        },
        tooltip: {
          trigger: "item",
        },
        legend: {
          orient: "vertical",
          left: "left",
        },
        series: [
          {
            name: "男女性别比例",
            type: "pie",
            radius: "50%",
            data: [
              {
                value: `${store.state.sex_totals.man_totals}`,
                name: "男",
              },
              {
                value: `${store.state.sex_totals.male_totals}`,
                name: "女",
              },
            ],
            emphasis: {
              itemStyle: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: "rgba(0, 0, 0, 0.5)",
              },
            },
          },
        ],
      });
      const arrSalaryRate = [];
      const axisX = [
        ">=3k&amp;&amp;<4k",
        ">=4k&amp;&amp;<5k",
        ">=5k&amp;&amp;<6k",
        ">=6k&amp;&amp;<8k",
        ">=8k&amp;&<10k",
        ">=10k&&<15k",
        ">=15k",
      ];
      // 遍历store.state.salaryRate值,储存到arrSalaryRate数组
      Object.values(store.state.salaryRate).forEach((value, index) => {
        arrSalaryRate[index] = value;
      });
      var myChart2 = echarts.init(document.querySelector("#center-main"));
      myChart2.setOption({
        title: {
          text: "员工工资占比",
          subtext: "努力工作,加油升资",
          left: "center",
        },
        tooltip: {
          trigger: "item",
          formatter: "{a} <br/>{b} : {c} ({d}%)",
        },
        legend: {
          left: "center",
          top: "bottom",
          data: axisX,
        },
        series: [
          {
            name: "Area Mode",
            type: "pie",
            radius: [20, 140],
            center: ["50%", "50%"],
            roseType: "area",
            itemStyle: {
              borderRadius: 5,
            },
            data: [
              {
                value: arrSalaryRate[0],

                name: ">=3k&&<4k",
              },
              {
                value: arrSalaryRate[1],

                name: ">=4k&&<5k",
              },
              {
                value: arrSalaryRate[2],

                name: ">=5k&&<6k",
              },
              {
                value: arrSalaryRate[3],
                name: ">=6k&&<8k",
              },
              {
                value: arrSalaryRate[4],
                name: ">=8k&&<10k",
              },
              {
                value: arrSalaryRate[5],
                name: ">=10k&&<15k",
              },
              {
                value: arrSalaryRate[6],
                name: ">=15k",
              },
            ],
          },
        ],
      });
      var months = [];
      // 存储每个月的工资
      store.state.getPersonalSalaryTotal.arr.forEach((item, index) => {
        months[index] = [
          `${item.Jan}`,
          `${item.Feb}`,
          `${item.Mar}`,
          `${item.Apr}`,
          `${item.May}`,
          `${item.Jun}`,
          `${item.Jul}`,
          `${item.Aug}`,
          `${item.Sep}`,
          `${item.Oct}`,
          `${item.Nov}`,
          `${item.Dec}`,
        ];
      });
      const myChart3_arr = [];
      store.state.getPersonalSalaryTotal.arr.forEach((item, index) => {
        myChart3_arr.push({
          name: `${item.employeeName}`,
          type: "line",
          data: months[index],
        });
      });
      var myChart3 = echarts.init(document.querySelector("#right-main"));
      myChart3.setOption({
        tooltip: {
          trigger: "axis",
        },
        legend: {
          data: [
            `${store.state.getPersonalSalaryTotal.arr[0].employeeName}`,
            `${store.state.getPersonalSalaryTotal.arr[1].employeeName}`,
            `${store.state.getPersonalSalaryTotal.arr[2].employeeName}`,
            `${store.state.getPersonalSalaryTotal.arr[3].employeeName}`,
          ],
        },
        grid: {
          left: "3%",
          right: "4%",
          bottom: "3%",
          containLabel: true,
        },
        xAxis: {
          type: "category",
          data: [
            "一月",
            "二月",
            "三月",
            "四月",
            "五月",
            "六月",
            "七月",
            "八月",
            "九月",
            "十月",
            "十一月",
            "十二月",
          ],
        },
        yAxis: {
          type: "value",
        },
        series: myChart3_arr,
      });
    });
  },
};
</script>
<template>
  <div class="rolesList-container">
    <div class="left-main" id="left-main"></div>
    <div class="center-main" id="center-main"></div>
    <div class="right-main" id="right-main"></div>
  </div>
</template>
<style lang="less" scoped>
.rolesList-container {
  height: 100%;
  width: 100%;
  display: flex;
  .left-main {
    flex: 2;
  }
  .center-main {
    flex: 3;
  }
  .right-main {
    flex: 6;
  }
}
</style>

首先将main.js中的代码清除,放置如下代码

引入import ElementPlus from “elementplus”;
importelementplus/dist/index.css”;
以及注册全局组件
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component);
}
此外,还要注册ElementPlus,即app.use(ElementPlus)

//main.js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
const app = createApp(App);
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component);
}
app.use(store).use(router).use(ElementPlus).mount("#app");

src目录下新建一个util目录,在util目录下新建一个api目录以及一个index.js文件

index.js中的代码

import axios from "axios";
const service = axios.create({
  baseURL: "http://localhost:80",
  timeout: 3000,
});
export default service;

api下面新建echarts.js文件以及employee.js文件

employee.js中的代码

写关于employee的api接口

import service from "../index";
// 登录
export function login(url, userNumber, password) {
  return service({
    method: "post",
    url: url,
    data: {
      userNumber,
      password,
    },
  });
}
// 获取员工表
export function getEmployees(url) {
  return service({
    method: "get",
    url: url,
  });
}

// 添加员工
export function addEmployees(url, values) {
  console.log(url, values);
  return service({
    method: "post",
    url: url,
    data: {
      empID: values.I,
      employeeName: values.N,
      employeePhone: values.P,
      employeeSex: values.S,
      employeeSalary: values.Sa,
      employeePosition: values.Po,
    },
  });
}
// 更新员工信息
export function updateEmployees(
  url,
  empID,
  employeePhone,
  employeeSalary,
  employeePosition
) {
  return service({
    method: "post",
    url: url,
    data: {
      empID,
      employeePhone,
      employeeSalary,
      employeePosition,
    },
  });
}
// 删除员工信息
export function deleteEmployees(url, empID) {
  return service({
    method: "delete",
    url: url,
    params: {
      empID,
    },
  });
}

echarts.js中的代码

写关于echarts的api接口。因为请求接口几乎一致,所以写一个就好了

import service from "../index";
export function seemURL(url) {
  return service({
    method: "get",
    url: url,
  });
}

首先将store目录下的index.js代码清除,然后放置如下代码:

import { createStore } from "vuex";
import { seemURL } from "@/util/api/echarts";
export default createStore({
  state: {
    sex_totals: {
      male_totals: "",
      man_totals: "",
    },
    salaryRate: {
      threeK: "",
      fourK: "",
      fiveK: "",
      sixK: "",
      eightK: "",
      tenK: "",
      firthK: "",
    },
    getPersonalSalaryTotal: {
      arr: [],
    },
  },
  getters: {},
  mutations: {
    getSex(state, value) {
      state.sex_totals.male_totals = value.male_total;
      state.sex_totals.man_totals = value.man_total;
    },
    getsalaryRate(state, value) {
      state.salaryRate.threeK = value.threeK;
      state.salaryRate.fourK = value.fourK;
      state.salaryRate.fiveK = value.fiveK;
      state.salaryRate.sixK = value.sixK;
      state.salaryRate.eightK = value.eightK;
      state.salaryRate.tenK = value.tenK;
      state.salaryRate.firthK = value.firthK;
    },
    getpersonalSalarytotals(state, value) {
      state.getPersonalSalaryTotal.arr = value;
    },
  },
  actions: {
    asyncGetSex(context) {
      const res = seemURL("/map_image/1");
      res.then((res) => {
        context.commit("getSex", res.data);
      });
    },
    asyncgetsalaryRate(context) {
      const res = seemURL("/map_image/2");
      res.then((res) => {
        context.commit("getsalaryRate", res.data);
      });
    },
    asyncgetpersonalSalarytotals(context) {
      const res = seemURL("/map_image/3");
      res.then((res) => {
        context.commit("getpersonalSalarytotals", res.data);
      });
    },
  },

  modules: {},
});

首先将router目录下的index.js代码清除,然后放置如下代码:

import { createRouter, createWebHashHistory } from "vue-router";

const routes = [
  {
    path: "/",
    name: "/",
    component: () => import("@/components/Layout.vue"),
    redirect: "/layout",
  },
  {
    path: "/login",
    name: "login",
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import("@/views/Login.vue"),
  },

  {
    path: "/layout",
    name: "layout",
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import("@/components/Layout.vue"),
    redirect: "/layout/userslist",
    children: [
      {
        path: "userslist",
        name: "userslist",
        // route level code-splitting
        // this generates a separate chunk (about.[hash].js) for this route
        // which is lazy-loaded when the route is visited.
        component: () => import("@/views/UsersList.vue"),
      },
      {
        path: "map",
        name: "map",
        // route level code-splitting
        // this generates a separate chunk (about.[hash].js) for this route
        // which is lazy-loaded when the route is visited.
        component: () => import("@/views/Map.vue"),
      },
    ],
  },
];

const router = createRouter({
  // 历史模式此处设置hash模式
  history: createWebHashHistory(),
  routes,
});
router.beforeEach((to, from, next) => {
  // 如果跳转目标不是/login
  if (to.path !== "/login") {
    // 并且存在本地记录,则放行
    if (localStorage.getItem("token")) {
      next();
    } else {
      //如果不存在本地记录,则强制跳转到登录界面
      next("/login");
    }
  } else {
    // 如果是跳转目标是/login,需要放行
    next();
  }
});
export default router;

启动项目 在项目名称下(比如shop)

npm run serve

node服务器代码区

新建一个目录(比如backstage)

新建一个js目录,目录下新建app.js以及router.js

初始化backstage

//生成package.josn
npm init -y

下载相关包

npm i cors --save
npm i express --save
npm i express-jwt --save
npm i josnwebtoken --save
npm i mysql --save
npm i nodemon -D

app.js中的代码

const express = require("express");

const app = express();

// 解析axios发送的josn数据,axios发送的data,默认是josn格式,而node默认urlencoded格式
app.use(express.json());
// 配置跨越请求
const cors = require("cors");

app.use(cors());
// 解析表单
app.use(express.urlencoded({ extended: false }));

const router = require("./router.js");

app.use("/", router);

app.listen("80", function () {
  console.log("为您服务");
});

router.js中的代码

为什么使用promise代码?本人在不使用promise时,造成了回调地狱问题,出于美观考虑,笔者还是决定使用promise,正好复习一些promise相关内容

const express = require("express");
const secretKey = "strongest ^0^";
const jwt = require("jsonwebtoken");
// express-jwt 最新版本使用方式,用于解析生成的token
// 解码后的 JWT 有效负载现在可用作 req.auth 而不是 req.user
// 我们只是为了获取token,并不需要解析token,不配置这个中间件也行
var { expressjwt: expressJWT } = require("express-jwt");
express().use(expressJWT({ secret: secretKey, algorithms: ["HS256"] }));

const router = express.Router();

const mysql = require("mysql");

const db = mysql.createPool({
  host: "127.0.0.1",
  user: "root",//你自己mysql登录用户名,一般都是root
  password: "123456",//你自己的mysql登录密码,比如你设置的123456
  port: "3306",
  // 连接数据库,//hrmsystem是(database)库的名字
  database: "hrmsystem",
});
// 员工查询操作
router.get("/employee", function (req, res) {
  db.query("SELECT * FROM employee", function (err, result) {
    console.log(result);
    const employees = result;
    if (err) return console.log(err.message);
    res.send(employees);
  });
});
// 登录操作
router.post("/login", function (req, res) {
  const tokenStr = jwt.sign({}, secretKey, {
    expiresIn: "10d",
  });
  db.query("SELECT * FROM register", function (err, result) {
    if (err) return console.log(err.message);
    if (result.some((item) => item.regID == req.body.userNumber)) {
      if (result.some((item) => item.regPassword == req.body.password)) {
        //发送token
        res.send({ status: 200, msg: "登录成功", token: `Bearer ${tokenStr}` });
      } else {
        res.send({ status: "error", msg: "密码错误" });
      }
    } else {
      res.send({ status: "error", msg: "账号存在" });
    }
  });
});
// 添加操作
router.post("/add", function (req, res) {
  db.query(`SELECT empID FROM employee `, function (err, result) {
    if (err) return console.log(err.message);
    if (
      result.some((item) => {
        item.empID == req.body.empID;
      })
    ) {
      res.send({ msg: "员工ID已经被注册过了,请更换ID" });
    } else {
      const sql = `insert into employee set ?`;
      const loop = {
        empID: req.body.empID,
        employeeName: req.body.employeeName,
        employeePhone: req.body.employeePhone,
        employeeSex: req.body.employeeSex,
        employeeSalary: req.body.employeeSalary,
        employeePosition: req.body.employeePosition,
      };
      db.query(
        sql,
        [
          loop,
          loop.ID,
          loop.name,
          loop.phone,
          loop.sex,
          loop.salary,
          loop.position,
        ],
        function (err, result) {
          if (err) {
            return console.log(err.message);
          }
          if (result.affectedRows === 1) {
            res.send({
              person: req.body,
              status: 200,
              msg: "添加员工成功",
            });
          }
        }
      );
    }
  });
});
// 更新操作
router.post("/update", function (req, res) {
  db.query(`SELECT empID FROM employee `, function (err, result) {
    // if (err) return console.log(err.message);

    if (result.some((item) => item.empID == req.body.empID)) {
      const sql = "update employee set ? where empID=?";
      // const sql = `update employee set employeePhone=${req.body.employeePhone} and employeeSalary=${req.body.employeeSalary} and  employeePosition=${req.body.employeePosition} where empID=${req.body.empID}`;
      const updateData = {
        employeePhone: req.body.employeePhone,
        employeeSalary: req.body.employeeSalary,
        employeePosition: req.body.employeePosition,
      };
      // db.query(sql, function (err, result) {
      db.query(sql, [updateData, req.body.empID], function (err, result) {
        if (err) return console.log(err.message);
        if (result.affectedRows === 1) {
          res.send({ status: 200, msg: "更改员工成功" });
        }
      });
    } else {
      res.send({ msg: "员工ID不存在" });
    }
  });
});
// 删除员工
router.delete("/delete", function (req, res) {
  db.query(
    `SELECT empID FROM employee where empID= ${req.query.empID}`,
    function (err, result) {
      console.log(result);
      console.log(req.query.empID);
      console.log(result.length > 0);
      if (result.length > 0) {
        const sql = `delete from employee where empID=?`;
        db.query(sql, (empID = req.query.empID), function (err, result) {
          if (err) return console.log(err.message);
          if (result.affectedRows === 1) {
            console.log(1);
            res.send({ status: 200, msg: "删除员工成功" });
          }
        });
      } else {
        res.send({ msg: "员工ID不存在" });
      }
    }
  );
});
router.get("/map_image/1", function (req, res) {
  let arr = [];
  let p = new Promise(function (resolve, reject) {
    db.query(
      ` SELECT * FROM employee where  employeeSex="男"`,
      function (err, result) {
        arr.push(result.length);
        if (err) return console.log(err.message);
        resolve(arr);
      }
    );
  });
  p.then((result) => {
    return new Promise((resolve, reject) => {
      db.query(
        ` SELECT * FROM employee where  employeeSex="女"`,
        function (err, result) {
          if (err) return console.log(err.message);
          arr.push(result.length);
          resolve(arr);
        }
      );
    });
  }).then(function (result) {
    res.send({ man_total: result[0], male_total: result[1] });
  }).catch((err) => {
      throw new Error(err.message);
    });;
});
router.get("/map_image/2", function (req, res) {
  let arr = [];
  let p = new Promise(function (resolve, reject) {
    db.query(
      ` SELECT * FROM employee where  employeeSalary>=3000 and employeeSalary<4000`,
      function (err, result) {
        arr.push(result.length);
        if (err) return console.log(err.message);
        resolve(arr);
      }
    );
  });
  p.then((result) => {
    return new Promise((resolve, reject) => {
      db.query(
        ` SELECT * FROM employee where  employeeSalary>=4000 and employeeSalary<5000`,
        function (err, result) {
          if (err) return console.log(err.message);
          arr.push(result.length);
          resolve(arr);
        }
      );
    });
  })
    .then((result) => {
      return new Promise((resolve, reject) => {
        db.query(
          ` SELECT * FROM employee where  employeeSalary>=5000 and employeeSalary<6000`,
          function (err, result) {
            if (err) return console.log(err.message);
            arr.push(result.length);
            resolve(arr);
          }
        );
      });
    })
    .then((result) => {
      return new Promise((resolve, reject) => {
        db.query(
          ` SELECT * FROM employee where  employeeSalary>=6000 and employeeSalary<8000`,
          function (err, result) {
            if (err) return console.log(err.message);
            arr.push(result.length);
            resolve(arr);
          }
        );
      });
    })
    .then((result) => {
      return new Promise((resolve, reject) => {
        db.query(
          ` SELECT * FROM employee where  employeeSalary>=8000 and employeeSalary<10000`,
          function (err, result) {
            if (err) return console.log(err.message);
            arr.push(result.length);
            resolve(arr);
          }
        );
      });
    })
    .then((result) => {
      return new Promise((resolve, reject) => {
        db.query(
          ` SELECT * FROM employee where  employeeSalary>=10000 and employeeSalary<15000`,
          function (err, result) {
            if (err) return console.log(err.message);
            arr.push(result.length);
            resolve(arr);
          }
        );
      });
    })
    .then((result) => {
      return new Promise((resolve, reject) => {
        db.query(
          ` SELECT * FROM employee where  employeeSalary>=15000`,
          function (err, result) {
            if (err) return console.log(err.message);
            arr.push(result.length);
            resolve(arr);
          }
        );
      });
    })
    .then(function (result) {
      console.log(result);
      res.send({
        threeK: result[0],
        fourK: result[1],
        fiveK: result[2],
        sixK: result[3],
        eightK: result[4],
        tenK: result[5],
        firthK: result[6],
      });
    }).catch((err) => {
      throw new Error(err.message);
    });;
});
router.get("/map_image/3", function (req, res) {
  db.query(` SELECT * FROM personal_salary`, function (err, result) {
    if (err) return console.log(err.message);
    res.send(result);
  });
});
// db.query("SELECT * FROM employee", function (err, result) {
//   if (err) return console.log(err.message);
//   console.log(result);
// });
// db.query("SELECT * FROM register", function (err, result) {
//   if (err) return console.log(err.message);
//   console.log(result);
// });
module.exports = router;

启动服务器 在js目录下

nodemon app.js

mysql相关内容

新建一个hrmsystem数据库

hrmsystem数据库中新建三张表,分别是employee和personal_salary以及register

相关字段下图所示

employee字段即empID,employeeName,employeePhone,employeeSex,employeeSalary,employeePosition
register字段 regID,regPasswordregisterName
personal_salary字段 empID Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec employeeName

总结

对于一个小白(特别是自学者)写一个前后结合的项目很不容易,特别是看别人的代码,没有注释那就更加难受了。这个前后结合项目,总体功能比较简单就是对拿到的数据进行增删改查操作。用了echarts进行可视化。希望这个项目能够对初学者能够有一定帮助。如果觉得有作用的话,不妨对作者进行一键三连(关注收藏,加点赞),谢谢各位啦!

原文地址:https://blog.csdn.net/qq_56889810/article/details/126120483

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_38758.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注