本篇主要探讨用户管理功能,接口部分依然是使用 Apifox mock 模拟。
1 用户 api
在 src/api/user.ts 中添加用户相关 CRUD 接口,代码如下:
//src/api/user.ts
import request from "@/api/config/request";
// 从 "./type" 模块中导入 ApiResponse 类型,用于定义接口响应数据的结构
import type { ApiResponse } from "./type";
import type { IRole } from "./role";/*** 定义用户登录所需的数据结构* @interface IUserLoginData* @property {string} username - 用户登录使用的用户名* @property {string} password - 用户登录使用的密码*/
export interface IUserLoginData {username: string;password: string;
}/*** 定义登录接口响应的数据结构* @interface ILoginResponseData* @property {string} token - 登录成功后返回的令牌,用于后续请求的身份验证*/
export interface ILoginResponseData {token: string;
}/*** 登录接口* @param {IUserLoginData} data - 用户登录所需的数据,包含用户名和密码* @returns {Promise<ApiResponse<ILoginResponseData>>} - 返回一个 Promise 对象,该对象解析为包含登录响应数据的 ApiResponse 类型*/
export const login = (data: IUserLoginData
): Promise<ApiResponse<ILoginResponseData>> => {return request.post("/4642164-4292760-default/287017559", data);
};
//test
export const logout_error = (): Promise<ApiResponse<ILoginResponseData>> => {return request.post("/4642164-4292760-default/auth/401");
};//个人中心接口
export interface Profile {id: number;username: string;email: string;mobile: string;isSuper: boolean;status: boolean;avatar: string;description: string;roles: IRole[];roleIds?: number[]; // 修改用户的时候,后端接受只要id
}export interface IUsers {users: Profile[];count: number;
}// 查询参数
export interface IUserQuery {pageNum?: number;pageSize?: number;mobile?: string;status?: boolean;username?: string;
}// 获取用户列表的接口
export const getUsers = (params: IUserQuery): Promise<ApiResponse<IUsers>> => {const {pageNum = 0,pageSize = 10,username = "",status,mobile = ""} = params;return request.get("/user", {params: {pageNum,pageSize,username,status,mobile}});
};// 删除用户
export const removeUser = (id: number): Promise<ApiResponse> => {return request.delete(`/user/${id}`);
};// 添加用户
export const addUser = (data: Profile): Promise<ApiResponse> => {return request.post("/auth/register", data);
};// 编辑用户
export const updateUser = (id: number, data: Profile): Promise<ApiResponse> => {return request.put(`/user/${id}`, data);
};
2 用户 Store
在 src/stores/user.ts 中添加用户相关方法,代码如下:
//src/stores/user.ts
import type { IUserLoginData, IUserQuery, IUsers, Profile } from "@/api/user";
import {login as loginApi,getUsers as getUsersApi, // 获取用户addUser as addUserApi,removeUser as removeUserApi,updateUser as updateUserApi
} from "@/api/user";
import { setToken, removeToken } from "@/utils/auth";
import { useTagsView } from "./tagsView";
import type { IRole } from "@/api/role";
export type IProfileQuery = Profile & {pageNum?: number;pageSize?: number;
};
export const useUserStore = defineStore("user", () => {const state = reactive({token: "",users: [] as IUsers["users"], // 用户列表count: 0, // 用户个数roles: [] as IRole[],userInfo: {} as Profile});const tagsViewStore = useTagsView();const login = async (userInfo: IUserLoginData) => {try {const { username, password } = userInfo;const response = await loginApi({ username: username.trim(), password });const { data } = response;state.token = data.token;setToken(data.token);} catch (e) {return Promise.reject(e);}};const logout = () => {state.token = "";removeToken();// 所有的信息都应该情况tagsViewStore.delAllView(); // ...};// 获取全部用户const getAllUsers = async (params: IUserQuery) => {const res = await getUsersApi(params);const { data } = res;state.users = data.users;state.count = data.count;};// 添加用户const addUser = async (data: IProfileQuery) => {const { pageSize, pageNum, ...params } = data;const res = await addUserApi(params);if (res.code === 0) {getAllUsers({pageSize,pageNum});}};// 删除用户const removeUser = async (data: IProfileQuery) => {const { pageSize, pageNum, id } = data;const res = await removeUserApi(id);if (res.code === 0) {getAllUsers({pageSize,pageNum});}};//编辑用户const editUser = async (data: IProfileQuery) => {const { pageSize, pageNum, ...params } = data;const res = await updateUserApi(params.id, params);if (res.code === 0) {getAllUsers({pageSize,pageNum});}};return {login,state,logout,getAllUsers,editUser,removeUser,addUser};
});
3 用户管理界面实现
3.1 editorUser 组件封装
在 src/views/system/user/components/editorUser.vue 中,实现用户新增编辑组件,代码如下:
//src/views/system/user/components/editorUser.vue
<template><div class="editor-container" p-20px><el-formref="editFormRef":model="editData":rules="menuFormRules"label-width="80px"><el-form-item label="用户名" prop="username"><el-input v-model="editData.username" placeholder="请输入用户名" /></el-form-item><el-form-item label="手机" prop="mobile"><el-inputv-model="editData.mobile"placeholder="请输入手机"maxlength="11"/></el-form-item><el-form-item label="邮箱" prop="email"><el-input v-model="editData.email" placeholder="请输入邮箱" /></el-form-item><el-form-item label="状态" prop="status"><el-switch v-model="editData.status" /></el-form-item><el-form-item label="角色分配" prop="roleIds"><el-select multiple v-model="editData.roleIds" placeholder="请选择角色"><el-optionv-for="item in editData.roles":key="item.id":label="item.name":value="item.id"></el-option></el-select></el-form-item><el-form-item label="说明" prop="description"><el-inputtype="textarea":rows="3"v-model="editData.description"placeholder="请输入说明"/></el-form-item><el-form-item><el-button type="primary" @click="submitMenuForm">提交</el-button></el-form-item></el-form></div>
</template><script lang="ts" setup>
import type { Profile } from "@/api/user";
import type { FormInstance, FormItemRule } from "element-plus";
import type { PropType } from "vue";const props = defineProps({type: {// 操作类型 0编辑 1新增type: Number,required: true},data: {type: Object as PropType<Profile>}
});
const emit = defineEmits(["submit"]);const editFormRef = ref<FormInstance | null>(null);
const editData = ref<Partial<Profile>>({username: "",email: "",mobile: "",description: "",status: true
});// 验证规则
const validateMobile = (rule: unknown,value: string,callback: (arg?: Error) => void
) => {if (!isNaN(Number(value)) && value.length === 11) {callback();}callback(new Error("请输入正确格式手机号!"));
};const menuFormRules = {username: {required: true,message: "请输入用户名",trigger: "blur"},email: [{required: true,message: "请输入邮箱",trigger: "blur"},{type: "email",message: "请输入正确的邮箱地址",trigger: ["blur", "change"]}] as FormItemRule[],mobile: [{required: true,message: "请输入手机",trigger: "blur"},{message: "请输入正确11位手机号",trigger: "blur",validator: validateMobile}],roleIds: {required: true,message: "请至少选择一个角色!",trigger: "blur"}
};const defaultProps = {username: "",email: "",mobile: "",description: "",status: true
};watchEffect(() => {if (props.data) {// 移除之前表单效验结果editFormRef.value?.clearValidate();editData.value = { ...defaultProps, ...props.data };}
});// 提交编辑菜单
const submitMenuForm = () => {(editFormRef.value as FormInstance).validate((valid) => {if (valid) {emit("submit", editData.value);}});
};
</script>
3.2 用户管理页面
在 src/views/system/user/index.vue 中,编写用户管理静态页面,代码如下:
//src/views/system/user/index.vue
<template><div class="user-container" p-30px><h2>用户管理</h2><el-button type="primary" plain @click="handleAddUser" class="mb">添加用户</el-button><el-form :inline="true" :model="formQuery" ref="queryFormRef"><el-form-item label="用户名" prop="username"><el-inputv-model="formQuery.username"placeholder="请输入用户名"></el-input></el-form-item><el-form-item label="手机号" prop="mobile"><el-inputv-model="formQuery.mobile"placeholder="请输入手机号"></el-input></el-form-item><el-form-item label="状态" prop="status" w-200px><el-select v-model="formQuery.status" placeholder="状态"><el-option label="全部" value="all"></el-option><el-option label="禁用" :value="0"></el-option><el-option label="正常" :value="1"></el-option></el-select></el-form-item><el-form-item><el-button type="primary" @click="handleSubmitQuery">查询</el-button><el-button type="default" @click="handleResetFeilds">重置</el-button></el-form-item></el-form><div class="user-list"><el-table :data="users" max-height="400"><el-table-column prop="username" label="用户名"> </el-table-column><el-table-column prop="mobile" label="手机"> </el-table-column><el-table-column prop="email" label="邮箱"> </el-table-column><el-table-column prop="status" label="状态" :formatter="formatter"></el-table-column><el-table-column prop="createdAt" label="创建时间"> </el-table-column><el-table-column label="操作" fixed="right" width="150px"><template #default="scope"><el-buttonsize="small"link@click="handleEditUser(scope.$index, scope.row)">编辑</el-button><el-buttonsize="small"link@click="handleDeleteUser(scope.$index, scope.row)">删除</el-button></template></el-table-column></el-table><div class="user-container"><div class="user-list"><!--用户展示--><div class="user-pagination"><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange"background:total="total":page-sizes="[1, 5, 10, 20]":page-size="pageSize"layout="total, prev, pager, next, sizes,jumper"></el-pagination></div></div></div></div><right-panel v-model="panelVisible" :title="panelTitle" :size="330"><editor-user:type="editType":data="editData"@submit="handleSubmitUser"/></right-panel></div>
</template><script lang="ts" setup>
import type { IUserQuery, Profile } from "@/api/user";
import { useRoleStore } from "@/stores/role";
import { type IProfileQuery, useUserStore } from "@/stores/user";
import type { FormInstance } from "element-plus";
const store = useUserStore();
// 用户列表
const users = computed(() => store.state.users);
// 分页相关状态
const pageNum = ref(0);
const pageSize = ref(10);
// 获取用户列表 支持分页
const getUserList = () => {store.getAllUsers({pageNum: pageNum.value,pageSize: pageSize.value,...formQuery// ... 搜索条件} as unknown as IUserQuery);
};
// 格式化status
const formatter = (row: Profile) => {return row.status ? "正常" : "禁用";
};
// 不使用watchEffect
onMounted(() => {getUserList();
});
// 删除用户
const { proxy } = getCurrentInstance()!;
const handleDeleteUser = async (index: number, row: Profile) => {try {await proxy?.$confirm(`您确认要删除用户${row.username}吗?`, "删除确认", {type: "warning"});await store.removeUser({id: row.id,pageNum: pageNum.value,pageSize: pageSize.value} as IProfileQuery);proxy?.$message.success("用户删除成功");} catch {proxy?.$message({type: "info",message: "已取消删除"});}
};
const handleEditUser = (index: number, row: Profile) => {editType.value = 0;editData.value = { ...row };// 获取当前编辑用户 现有角色列表editData.value.roleIds = row.roles.map((item) => item.id);editData.value.roles = roles.value!; // 所有角色列表panelVisible.value = true;
};
// 用户总条数
const total = computed(() => store.state.count);
// 分页
const handleSizeChange = (val: number) => {pageSize.value = val;getUserList();
};
const handleCurrentChange = (val: number) => {pageNum.value = val - 1; // 页码后端是从0开始的getUserList();
};// 查询参数
const formQuery = reactive({username: "",status: "all",mobile: ""
});
const handleSubmitQuery = () => {getUserList();
};// 重置
const queryFormRef = useTemplateRef<FormInstance | null>("queryFormRef");
const handleResetFeilds = () => {(queryFormRef.value as FormInstance).resetFields();getUserList();
};const editData = ref<Profile | undefined>(undefined);
// 控制面板显示
const panelVisible = ref(false);
const editType = ref(1);
const panelTitle = computed(() =>editType.value === 1 ? "新增用户" : "编辑用户"
);
const storeRole = useRoleStore();
storeRole.getRoles({pageNum: pageNum.value,pageSize: pageSize.value,flag: 0
});
const roles = computed(() => storeRole.state.roles); // 角色const handleAddUser = () => {editType.value = 1;editData.value = {} as Profile;editData.value.roles = roles.value; // 所有角色列表editData.value.roleIds = []; // 所选角色id列表panelVisible.value = true;
};
const editUser = async (data: IProfileQuery) => {store.editUser({...data,pageSize: pageSize.value,pageNum: pageNum.value});(queryFormRef.value as FormInstance).resetFields();proxy?.$message.success("用户编辑成功");panelVisible.value = false;
};
const handleSubmitUser = (data: Profile) => {if (editType.value === 1) {// 新增addNewUser(data);} else {editUser(data);}
};
const addNewUser = (data: Profile) => {store.addUser({...data,pageSize: pageSize.value,pageNum: pageNum.value});(queryFormRef.value as FormInstance).resetFields();proxy?.$message.success("用户添加成功");panelVisible.value = false;
};
</script>
npm run dev 启动后,页面效果如下:
以上,就是用户管理的全部内容。
下一篇将继续探讨 菜单管理,敬请期待~