Vue + ElementPlus 实现权限管理系统(九): 实现用户管理功能

701 阅读5分钟

在权限管理系统中,用户管理是一个非常重要的功能,它可以让管理员对系统中的用户进行添加、修改、删除、禁用和查询等操作,从而实现对系统的安全管理和用户的权限控制。本篇文章将详细介绍前端如何实现用户管理功能。

接口定义

首先我们在api/user/index.ts定义一下需要调用的接口。

import request from "@/utils/http/index";
import { Form, QueryParams } from "./types/user.dto";

//获取用户列表
export const getDataList = (query: QueryParams) => {
  return request({
    url: "/user/list",
    method: "get",
    params: query,
  });
};

//新增
export const addData = (data: Form) => {
  return request({
    url: "/user/createUser",
    data,
    method: "post",
  });
};

//更新
export const updateData = (data: Form) => {
  return request({
    url: "/user/updateUser",
    data,
    method: "put",
  });
};

//删除
export const deleteData = (id: number | number[]) => {
  return request({
    url: `/user/deleteUser/${id}`,
    method: "delete",
  });
};

然后我们在src/views/user/index.vue中实现一下页面。

用户查询

角色的查询我们需要传入用户名,状态,开始时间,结束时间,分页信息,我们将查询条件写在form

<template>
 <el-form :model="queryParams" ref="queryRef" :inline="true">
      <el-form-item label="用户名称">
        <el-input
          v-model="queryParams.username"
          placeholder="用户名称"
          class="w-[150px]"
          clearable
        />
      </el-form-item>
      <el-form-item label="状态" prop="status" class="w-[150px]">
        <el-select
          v-model="queryParams.status"
          placeholder="用户状态"
          clearable
        >
          <el-option
            v-for="dict in dickStatus"
            :key="dict.value"
            :label="dict.label"
            :value="dict.value"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="创建时间" style="width: 308px">
        <el-date-picker
          v-model="dateRange"
          value-format="YYYY-MM-DD"
          type="daterange"
          range-separator="-"
          start-placeholder="开始日期"
          end-placeholder="结束日期"
        ></el-date-picker>
      </el-form-item>
      <el-form-item>
        <el-button
          type="primary"
          v-hasPerm="['system:user:list']"
          icon="Search"
          @click="handleQuery"
          >搜索</el-button
        >
      </el-form-item>
      </el-form>
</template>
<script lang="ts" setup>
...
const queryParams = reactive<QueryParams>({
  username: "",
  status: "",
  telephone: "",
  begin_time: "",
  end_time: "",
  page_num: 1,
  page_size: 10,
});

const dateRange = ref<any>([]);
const dickStatus = [
  {
    label: "启用",
    value: 1,
  },
  {
    label: "禁用",
    value: 0,
  },
];

const total = ref(0);
const tableData = ref<DataItem[]>([]);
</script>

其中搜索按钮赋值了system:user:list权限,如果没有将不会展示。所以我们需要提前在菜单管理中新增一下这些权限。这里我已经提前加上了

image.png

查询的数据需要展示在表格中,我们可以使用el-table来展示。同时引入el-pagination来实现分页。


    <el-table :data="tableData" class="w-full mt-2" row-key="id" border>
      <el-table-column prop="username" label="用户名" />

      <el-table-column prop="nickname" label="昵称" />
      <el-table-column prop="telephone" label="手机号" />
      <el-table-column prop="email" label="邮箱" />
      <el-table-column prop="status" label="状态" width="80">
        <template #default="scope">
          <el-switch
            @change="changeStatus(scope.row)"
            :model-value="!!scope.row.status"
          ></el-switch>
        </template>
      </el-table-column>

      <el-table-column prop="create_time" label="创建时间" />
      <el-table-column prop="update_time" label="更新时间" />

      <el-table-column
        label="操作"
        align="center"
        width="200"
        class-name="small-padding fixed-width"
      >
        <template #default="scope">
          <el-link
            type="primary"
            icon="Edit"
            class="mr-1"
            v-hasPerm="['system:user:edit']"
            @click="handleUpdate(scope.row)"
            >修改</el-link
          >
          <el-link
            type="danger"
            icon="Delete"
            v-hasPerm="['system:user:delete']"
            @click="handleDelete(scope.row)"
            >删除</el-link
          >
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      v-show="total > 0"
      background
      class="p-5"
      layout="total,sizes, prev, pager, next"
      :total="total"
      v-model:current-page="queryParams.page_num"
      v-model:page-size="queryParams.page_size"
      @change="getList"
    />

定义表格数据及分页参数,同时调用查询接口获取数据。

import { getDataList, updateData, addData, deleteData } from "@/api/user/index";
const total = ref(0);
const tableData = ref<DataItem[]>([]);
const getList = async () => {
// 处理时间范围
  handleDateRangeChange(dateRange.value, queryParams);
  const { data } = await getDataList(queryParams);
  tableData.value = data.list;
  total.value = data.total;
};

getList();

这样就实现了用户的查询功能。

image.png

新增用户及修改用户

新增用户和修改用户的逻辑是一样的,我们可以使用一个弹窗来实现。

    <el-dialog
      :title="isUpdate ? '修改' : '新增'"
      width="500px"
      v-model="dialogVisible"
      append-to-body
    >
      <el-form
        :model="form"
        ref="ruleFormRef"
        :rules="rules"
        label-width="100px"
      >
        <el-form-item label="用户名称" prop="username">
          <el-input v-model="form.username" placeholder="请输入用户名称" />
        </el-form-item>
        <el-form-item label="密码" prop="password" v-if="!isUpdate">
          <el-input v-model="form.password" placeholder="请输入密码" />
        </el-form-item>
        <el-form-item label="昵称" prop="nickname">
          <el-input v-model="form.nickname" placeholder="请输入昵称" />
        </el-form-item>
        <el-form-item label="手机号" prop="telephone">
          <el-input v-model="form.telephone" placeholder="请输入手机号" />
        </el-form-item>
        <el-form-item label="邮箱" prop="email">
          <el-input v-model="form.email" placeholder="请输入邮箱" />
        </el-form-item>

        <el-form-item label="显示状态">
          <el-radio-group v-model="form.status">
            <el-radio
              v-for="dict in dickStatus"
              :key="dict.value"
              :label="dict.label"
              :value="dict.value"
            ></el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="角色">
          <el-select
            v-model="form.role_ids"
            multiple
            placeholder="选择角色"
            style="width: 240px"
          >
            <el-option
              v-for="item in roleOptions"
              :key="item.id"
              :label="item.role_name"
              :value="item.id"
            />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm(ruleFormRef)"
            >确 定</el-button
          >
          <el-button @click="cancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>

然后定义一下其中的form参数,rules规则及重置 form 的函数。

const dialogVisible = ref(false);
//是否是更新操作
const isUpdate = ref(false);
const form = ref<Form>({} as Form);
const rules = ref({
  username: [{ required: true, message: "用户名称不能为空", trigger: "blur" }],
  password: [
    {
      required: true,
      message: "密码必须是6~16位",
      trigger: "blur",
      min: 6,
      max: 16,
    },
  ],
  email: [
    {
      validator: validate_email,
      message: "邮箱格式不正确",
      trigger: "blur",
      required: true,
    },
  ],
  telephone: [
    {
      validator: validate_phoneNumber,
      message: "手机号格式不正确",
      trigger: "blur",
      required: true,
    },
  ],
});
const resetForm = () => {
  form.value = {
    username: "",
    email: "",
    status: 1,
    nickname: "",
    telephone: "",
  };
};

其中涉及到的类型如Form都写到了api/user/types/user.dto.ts中。

export type QueryParams = {
  username?: string,
  status?: number | "",
  telephone?: string,
  end_time?: string,
  begin_time?: string,
  page_num?: number,
  page_size?: number,
};

export type DataItem = {
  id: number,
  username: string,
  nickname: string,
  avatar: string,
  telephone: string,
  email: string,
  status: number,
  is_admin: number,
  create_time: Date,
  update_time: Date,
};

export type Form = {
  id?: number,
  username?: string,
  nickname?: string,
  avatar?: string,
  telephone?: string,
  email?: string,
  status?: number,
  role_ids?: number[],
  password?: string,
};

其中我们需要给用户赋予角色,所以我们需要调用角色的接口获取角色列表,新增或修改的时候可以选择

const roleOptions = ref<RoleList[]>([]);
const getRoleListData = async () => {
  const { data } = await getRoleList({});
  roleOptions.value = data.list;
};
getRoleListData();

最后根据isUpdate来判断是新增还是修改。从而调用不同接口

//新增
const handleAdd = () => {
  resetForm();
  dialogVisible.value = true;
  isUpdate.value = false;
};

//编辑
const handleUpdate = (row: Form & { roles?: RoleList[] }) => {
  resetForm();

  isUpdate.value = true;
  form.value = deepClone(row);
  form.value.role_ids = row.roles?.map((item) => item.id);

  dialogVisible.value = true;
};
const submitForm = async (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  await formEl.validate(async (valid, fields) => {
    if (valid) {
      const action = isUpdate.value ? updateData : addData;
      const successMessage = isUpdate.value ? "修改成功" : "添加成功";
      await action(form.value);
      dialogVisible.value = false;
      ElMessage.success(successMessage);
      getList();
    } else {
      console.log("error submit!", fields);
    }
  });
};

同时表格中可以通过el-switch操作对用户进行禁用和启用操作。也是调用修改接口

//更新状态
const changeStatus = async (row: DataItem) => {
  const uptateRow: Form = {} as Form;
  uptateRow.status = row.status === 1 ? 0 : 1;
  uptateRow.id = row.id;

  await updateData(uptateRow);
  ElMessage({
    type: "success",
    message: "状态更新成功",
  });
  getList();
};

ok,到这里便实现了用户的新增和修改功能。如下图所示

image.png

删除用户

最后实现删除用户功能,这就很简单了,通过传入的 id 来调用删除接口即可。

//删除
const handleDelete = async (row: DataItem) => {
  await ElMessageBox.confirm("确认删除吗?", "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
  });

  await deleteData(row.id);
  ElMessage({
    type: "success",
    message: "删除成功",
  });
  getList();
};

不知道各位小伙伴发现没有用户管理和角色管理实现起来差不多,其实后面的各种管理功能都是类似的,不止前端代码,后端亦如此。所以后续将会实现一个代码生成的功能,根据不同的表结构生成对应的代码。而你只需要稍作改动便能轻松实现你想要的功能。

自此我们的权限管理系统的架子基本实现了,后续的功能将是在此基础上添砖加瓦,最后一步步打造成一个完整的系统,敬请期待!

源码地址