Appearance
本篇主要探讨用户管理功能,接口部分依然是使用 Apifox mock 模拟。
用户 api
在 src/api/user.ts 中添加用户相关 CRUD 接口,代码如下:
typescript
//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);
};用户 Store
在 src/stores/user.ts 中添加用户相关方法,代码如下:
typescript
//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.1 editorUser 组件封装
在 src/views/system/user/components/editorUser.vue 中,实现用户新增编辑组件,代码如下:
html
//src/views/system/user/components/editorUser.vue
<template>
<divclass="editor-container"p-20px>
<el-form
ref="editFormRef"
:model="editData"
:rules="menuFormRules"
label-width="80px"
>
<el-form-itemlabel="用户名"prop="username">
<el-inputv-model="editData.username"placeholder="请输入用户名" />
</el-form-item>
<el-form-itemlabel="手机"prop="mobile">
<el-input
v-model="editData.mobile"
placeholder="请输入手机"
maxlength="11"
/>
</el-form-item>
<el-form-itemlabel="邮箱"prop="email">
<el-inputv-model="editData.email"placeholder="请输入邮箱" />
</el-form-item>
<el-form-itemlabel="状态"prop="status">
<el-switchv-model="editData.status" />
</el-form-item>
<el-form-itemlabel="角色分配"prop="roleIds">
<el-selectmultiplev-model="editData.roleIds"placeholder="请选择角色">
<el-option
v-for="item in editData.roles"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
<el-form-itemlabel="说明"prop="description">
<el-input
type="textarea"
:rows="3"
v-model="editData.description"
placeholder="请输入说明"
/>
</el-form-item>
<el-form-item>
<el-buttontype="primary" @click="submitMenuForm">提交</el-button>
</el-form-item>
</el-form>
</div>
</template>
<scriptlang="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 中,编写用户管理静态页面,代码如下:
html
//src/views/system/user/index.vue
<template>
<divclass="user-container"p-30px>
<h2>用户管理</h2>
<el-buttontype="primary"plain @click="handleAddUser"class="mb">
添加用户</el-button
>
<el-form:inline="true":model="formQuery"ref="queryFormRef">
<el-form-itemlabel="用户名"prop="username">
<el-input
v-model="formQuery.username"
placeholder="请输入用户名"
></el-input>
</el-form-item>
<el-form-itemlabel="手机号"prop="mobile">
<el-input
v-model="formQuery.mobile"
placeholder="请输入手机号"
></el-input>
</el-form-item>
<el-form-itemlabel="状态"prop="status"w-200px>
<el-selectv-model="formQuery.status"placeholder="状态">
<el-optionlabel="全部"value="all"></el-option>
<el-optionlabel="禁用":value="0"></el-option>
<el-optionlabel="正常":value="1"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-buttontype="primary" @click="handleSubmitQuery">查询</el-button>
<el-buttontype="default" @click="handleResetFeilds">重置</el-button>
</el-form-item>
</el-form>
<divclass="user-list">
<el-table:data="users"max-height="400">
<el-table-columnprop="username"label="用户名"></el-table-column>
<el-table-columnprop="mobile"label="手机"></el-table-column>
<el-table-columnprop="email"label="邮箱"></el-table-column>
<el-table-columnprop="status"label="状态":formatter="formatter">
</el-table-column>
<el-table-columnprop="createdAt"label="创建时间"></el-table-column>
<el-table-columnlabel="操作"fixed="right"width="150px">
<template #default="scope">
<el-button
size="small"
link
@click="handleEditUser(scope.$index, scope.row)"
>编辑</el-button
>
<el-button
size="small"
link
@click="handleDeleteUser(scope.$index, scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<divclass="user-container">
<divclass="user-list">
<!--用户展示-->
<divclass="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-panelv-model="panelVisible":title="panelTitle":size="330">
<editor-user
:type="editType"
:data="editData"
@submit="handleSubmitUser"
/>
</right-panel>
</div>
</template>
<scriptlang="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 启动后,页面效果如下:

以上,就是用户管理的全部内容。