本篇主要探討用戶管理功能,接口部分依然是使用 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 啟動后,頁面效果如下:
以上,就是用戶管理的全部內容。
下一篇將繼續探討 菜單管理,敬請期待~?