添加、编辑
用的是同一个编辑面板
1-1 user.vue
添加用户就等于注册用户,目前密码默认都是6个1
src/views/system/user/index.vue
<template>
<div class="user-container">
<h2>用户管理</h2>
<el-form :inline="true" :model="formQuery" ref="queryFormRef">
<el-form-item label="用户名" prop="username">
<el-input v-model="formQuery.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input v-model="formQuery.mobile" placeholder="请输入手机号"></el-input>
</el-form-item>
<el-form-item label="状态" prop="status">
<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="role-list">
<el-button
type="primary"
plain
icon="el-icon-plus"
@click="handleAddUser"
>添加用户</el-button>
<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-button
type="text"
size="mini"
@click="handleEditUser(scope.$index, scope.row)">编辑</el-button>
<el-button
type="text"
size="mini"
@click="handleDeleteUser(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<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>
<!-- 新增角色 编辑角色面板 -->
<right-panel v-model="panelVisible" :title="panelTitle" :size="330">
<editor-user
:type="editType"
:data="editData"
@submit="handleSubmitUser"
/>
</right-panel>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, onMounted, reactive, ref, getCurrentInstance } from 'vue'
import { ElForm } from 'element-plus'
import { Profile } from '@/store/modules/user'
import { useStore } from '@/store'
import RightPanel from '@/components/RightPanel/index.vue'
import EditorUser from './components/editorUser.vue'
type ElFormInstance = InstanceType<typeof ElForm>
export default defineComponent({
name: 'User',
components: {
EditorUser,
RightPanel
},
setup() {
const { proxy } = getCurrentInstance()!
const store = useStore()
// 查询表单ref
const queryFormRef = ref<ElFormInstance | null>(null)
// 查询条件
const formQuery = reactive({
username: '',
status: 'all',
mobile: ''
})
// 用户列表
const users = computed(() => store.state.user.users)
// 用户总条数
const total = computed(() => store.state.user.count)
// 分页相关状态
const pageNum = ref(0)
const pageSize = ref(1)
// 获取用户列表 支持分页
const getUserList = () => {
store.dispatch('user/getAllUsers', {
pageNum: pageNum.value,
pageSize: pageSize.value,
...formQuery
})
}
onMounted(() => { // 初始加载数据
getUserList()
})
// 查询
const handleSubmitQuery = () => {
getUserList()
}
// 重置
const handleResetFeilds = () => {
(queryFormRef.value as ElFormInstance).resetFields()
getUserList()
}
// 分页
const handleSizeChange = (val: number) => {
pageSize.value = val
getUserList()
}
const handleCurrentChange = (val: number) => {
pageNum.value = val - 1 // 页码后端是从0开始的
getUserList()
}
// 格式化status
const formatter = (row: Profile) => {
return row.status ? '正常' : '禁用'
}
// 用户新增
const editData = ref<Profile | undefined>(undefined)
// 控制面板显示
const panelVisible = ref(false)
// 操作类型 0编辑 1新增
const editType = ref(1)
// panel title
const panelTitle = computed(() => editType.value === 1 ? '新增用户' : '编辑用户')
// 获取角色 添加和编辑用户都需要分配角色 这里是必选
store.dispatch('role/getRoles')
const roles = computed(() => store.state.role.roles)
// 添加用户
const handleAddUser = () => {
editType.value = 1
editData.value = {} as Profile
editData.value.roles = roles.value // 所有角色列表
editData.value.roleIds = [] // 所选角色id列表
panelVisible.value = true
}
// 编辑用户
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 dispatchAction = async (action: string, data: Partial<Profile>, message: string) => {
await store.dispatch(action, {
...data,
pageSize: pageSize.value,
pageNum: pageNum.value
}).then(() => {
(queryFormRef.value as ElFormInstance).resetFields()
proxy?.$message.success(message)
panelVisible.value = false
})
}
// 新增用户
const addNewUser = (data: Profile) => {
dispatchAction('user/addUser', data, '用户添加成功')
}
// 编辑用户
const editUser = (data: Profile) => {
dispatchAction('user/editUser', data, '用户编辑成功')
}
// 删除用户
const handleDeleteUser = (index: number, row: Profile) => {
proxy?.$confirm(`您确认要删除用户${row.username}吗?`, '删除确认', {
type: 'warning'
}).then(async () => {
await dispatchAction('user/removeUser', {
id: row.id
}, '用户删除成功')
}).catch((err: Error) => {
console.log('err', err)
proxy?.$message({
type: 'info',
message: '已取消删除'
})
})
}
// 提交用户信息
const handleSubmitUser = (data: Profile) => {
if (editType.value === 1) { // 新增
addNewUser(data)
} else if (editType.value === 0) { // 编辑
editUser(data)
}
}
return {
users,
total,
pageSize,
formQuery,
queryFormRef,
formatter,
editData,
panelVisible,
editType,
panelTitle,
handleSubmitUser,
handleAddUser,
handleEditUser,
handleDeleteUser,
handleSizeChange,
handleCurrentChange,
handleSubmitQuery,
handleResetFeilds
}
}
})
</script>
<style lang="scss" scoped>
.user-container {
padding: 30px;
.user-pagination {
margin-top: 10px;
text-align: right;
}
}
</style>
创建editorUser组件
/src/views/system/user/components/editorUser.vue
<template>
<div class="editor-container">
<el-form
ref="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-input
v-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-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-item label="说明" prop="description">
<el-input
type="textarea"
:rows="3"
v-model="editData.description"
placeholder="请输入说明"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitMenuForm" :loading="loading"
>提交</el-button
>
</el-form-item>
</el-form>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, watchEffect } from 'vue'
import { ElForm } from 'element-plus'
import { Profile } from '@/store/modules/user'
type FormInstance = InstanceType<typeof ElForm>
export default defineComponent({
name: 'EditorMenu',
props: {
type: { // 操作类型 0编辑 1新增
type: Number,
required: true
},
data: {
type: Object as PropType<Profile>
}
},
emits: ['submit'],
setup(props, { emit }) {
const loading = ref(false)
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 validateRoles = (
rule: unknown,
value: number[],
callback: (arg?: Error) => void
) => {
if (value.length <= 0) {
callback(new Error('请至少选择一个角色!'))
}
callback()
}
const menuFormRules = {
username: {
required: true,
message: '请输入用户名',
trigger: 'blur'
},
email: [
{
required: true,
message: '请输入邮箱',
trigger: 'blur'
},
{
type: 'email',
message: '请输入正确的邮箱地址',
trigger: ['blur', 'change']
}
],
mobile: [
{
required: true,
message: '请输入手机',
trigger: 'blur'
},
{
message: '请输入正确11位手机号',
trigger: 'blur',
validator: validateMobile
}
],
roleIds: {
required: true,
message: '请至少选择一个角色!',
// validator: validateRoles,
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)
}
})
}
return {
editData,
submitMenuForm,
editFormRef,
menuFormRules,
loading
}
}
})
</script>
<style>
.editor-container {
padding: 20px;
}
</style>
1-2 相关store
至于上面页面中 需要依赖角色数据,至于角色的sotre放在角色那一章节
src/store/modules/user.ts
import { Module, MutationTree, ActionTree } from 'vuex'
import { IRootState } from '@/store'
import { getUserInfo, getUsers, login, addUser, updateUser, removeUser } from '@/api/user'
import { setToken, removeToken, getToken } from '@/utils/auth'
// login params
export interface IUserInfo {
username: string;
password: string;
}
interface Role {
id: number;
name: string;
description: string;
}
export interface Profile {
avatar: string;
email: string;
id: number;
isSuper: boolean;
mobile: string;
status: boolean;
username: string;
description: string;
roles: Role[];
roleIds?: number[]
}
// 定义state类型
export interface IUserState {
token: string | null;
userInfo: Profile | null;
users: Profile[];
count: number;
roles: Role[] | null
}
// 查询user参数类型
export interface IUserQuery {
pageNum?: number;
pageSize?: number;
mobile?: string;
status?: boolean;
username?: string;
}
// 用户编辑/添加查询类型
export type IProfileQuery = Profile & {
pageNum?: number;
pageSize?: number;
}
// mutations类型
type IMutations = MutationTree<IUserState>
// actions类型
type IActions = ActionTree<IUserState, IRootState>
// 定义state
const state: IUserState = {
token: getToken(),
userInfo: null,
users: [],
count: 0,
roles: null
}
// 定义mutation
const mutations: IMutations = {
SET_TOKEN(state, token: string) {
state.token = token
},
SET_USER_INFO(state, data: Profile) {
state.userInfo = data
},
SET_USERS(state, data: Profile[]) {
state.users = data
},
SET_COUNT(state, data: number) {
state.count = data
},
SET_ROLES(state, data: Role[]) {
state.roles = data
}
}
// 定义action
const actions: IActions = {
login({ commit }, userInfo: IUserInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
login({ username: username.trim(), password }).then(response => {
const { data } = response
commit('SET_TOKEN', data.token)
setToken(data.token) // localStorage中保存token
resolve(data)
}).catch(error => {
reject(error)
})
})
},
logout({ commit, dispatch }) {
// 退出登录接口我这里就不写了
return new Promise<void>((resolve) => {
// 清空store里token
commit('SET_TOKEN', '')
// 清空localStorage里的token
removeToken()
// 清除所有tag views
dispatch('tagsView/delAllViews', null, { root: true })
resolve()
})
},
resetToken({ commit }) {
return new Promise<void>((resolve) => {
// 清空store里token
commit('SET_TOKEN', '')
// 清空localStorage里的token
removeToken()
resolve()
})
},
getAllUsers({ commit }, params: IUserQuery = {}) {
return new Promise<void>((resolve, reject) => {
getUsers(params).then(res => {
const { data } = res
commit('SET_USERS', data.users)
commit('SET_COUNT', data.count)
resolve()
}).catch(reject)
})
},
addUser({ dispatch }, data: IProfileQuery) {
return new Promise<void>((resolve, reject) => {
const { pageSize, pageNum, ...params } = data
addUser(params).then(res => {
if (res.code === 0) {
dispatch('getAllUsers', {
pageSize,
pageNum
})
}
resolve()
}).catch(reject)
})
},
editUser({ dispatch }, data: IProfileQuery) {
return new Promise<void>((resolve, reject) => {
const { pageSize, pageNum, ...params } = data
updateUser(params.id, params).then(res => {
if (res.code === 0) {
dispatch('getAllUsers', {
pageSize,
pageNum
})
}
resolve()
}).catch(reject)
})
},
removeUser({ dispatch }, data: IProfileQuery) {
return new Promise<void>((resolve, reject) => {
const { pageSize, pageNum, id } = data
removeUser(id).then(res => {
if (res.code === 0) {
dispatch('getAllUsers', {
pageSize,
pageNum
})
}
resolve()
}).catch(reject)
})
},
getUserInfo({ commit }) {
return new Promise((resolve, reject) => {
getUserInfo().then(response => {
const { data } = response
const { roles, ...info } = data
commit('SET_USER_INFO', info)
commit('SET_ROLES', roles)
resolve(roles)
}).catch(reject)
})
}
}
// 定义user module
const user: Module<IUserState, IRootState> = {
namespaced: true,
state,
mutations,
actions
}
export default user
1-3 用户相关api
src/api/user.ts
import request from '@/api/config/request'
import { IUserQuery, Profile } from '@/store/modules/user'
import { ApiResponse } from './type'
interface UserLoginData {
username: string;
password: string;
}
interface LoginResponseData {
token: string;
}
export const login = (data: UserLoginData): Promise<ApiResponse<LoginResponseData>> => {
return request.post(
'/auth/login',
data
)
}
// 获取用户信息
interface UserBody {
token: string;
}
export const getUserInfo = (data?: UserBody): Promise<ApiResponse<Profile>> => {
return request.post('/auth/info', data)
}
// 获取用户列表
interface IUsers {
users: Profile[];
count: number;
}
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)
}