Commit ed067bf3 authored by 何远江's avatar 何远江

添加用户,账号管理,优化表格查询

parent d5e6751e
import request from '@/utils/http/index';
export const saveMenu = (data) => {
return request.post('/menu/save', data);
};
export const getMenuTree = (params) => {
return request.get('/menu/menuTree', params);
};
export const deleteMenus = (ids) => {
return request.get('/menu/batchDeleteByIds', { ids });
};
import request from '@/utils/http/index';
export const saveRole = (data) => {
return request.post('/role/save', data);
};
export const getRolePage = (params) => {
return request.get('/role/page', params);
};
export const deleteRoles = (ids) => {
return request.get('/role/batchDeleteByIds', { ids });
};
import request from '@/utils/http/index';
export const saveTenant = (data) => {
return request.post('/tenant/save', data);
};
export const getTenantPage = () => {
return request.get('/tenant/page');
};
export const deleteTenants = (ids) => {
return request.get('/tenant/batchDeleteByIds', { ids });
};
import request from '@/utils/http/index';
export const saveUser = (data) => {
return request.post('/login/save', data);
};
export const getUserPage = (params) => {
return request.get('/login/page', params);
};
export const deleteUsers = (ids) => {
return request.get('/login/batchDeleteByIds', { ids });
};
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
<!-- 分页组件 --> <!-- 分页组件 -->
<el-pagination <el-pagination
:background="true" :background="true"
:current-page="pageable.pageNum" :current-page="pageable.current"
:page-size="pageable.pageSize" :page-size="pageable.size"
:page-sizes="[10, 25, 50, 100]" :page-sizes="[10, 25, 50, 100]"
:total="pageable.total" :total="pageable.total"
:size="globalStore?.assemblySize ?? 'default'" :size="globalStore?.assemblySize ?? 'default'"
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<!-- 表格主体 --> <!-- 表格主体 -->
<div> <div>
<slot name="table_top"></slot> <slot name="table_top"></slot>
<vxe-grid ref="xGrid" v-bind="gridOptions" :data="processTableData"> <vxe-grid ref="xGrid" v-bind="gridOptions" :data="processTableData" :loading="loading">
<template #toolbar_buttons> <template #toolbar_buttons>
<slot name="left_buttons"></slot> <slot name="left_buttons"></slot>
</template> </template>
...@@ -80,13 +80,13 @@ ...@@ -80,13 +80,13 @@
}, },
data: { data: {
type: Array, type: Array,
default: () => [],
}, },
}); });
const xGrid = ref(null); const xGrid = ref(null);
const { const {
tableData, tableData,
loading,
pageable, pageable,
gridConfig, gridConfig,
searchParam, searchParam,
......
...@@ -2,14 +2,15 @@ import { reactive, toRefs, computed } from 'vue'; ...@@ -2,14 +2,15 @@ import { reactive, toRefs, computed } from 'vue';
export function useProTable(api, initParam = {}, isPageable, dataCallBack, requestError) { export function useProTable(api, initParam = {}, isPageable, dataCallBack, requestError) {
const state = reactive({ const state = reactive({
loading: false,
// 表格数据 // 表格数据
tableData: [], tableData: [],
// 分页数据 // 分页数据
pageable: { pageable: {
// 当前页数 // 当前页数
pageNum: 1, current: 1,
// 每页显示条数 // 每页显示条数
pageSize: 10, size: 10,
// 总条数 // 总条数
total: 0, total: 0,
}, },
...@@ -42,8 +43,8 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque ...@@ -42,8 +43,8 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque
const pageParam = computed({ const pageParam = computed({
get: () => { get: () => {
return { return {
pageNum: state.pageable.pageNum, current: state.pageable.current,
pageSize: state.pageable.pageSize, size: state.pageable.size,
}; };
}, },
set: (newVal) => { set: (newVal) => {
...@@ -58,18 +59,22 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque ...@@ -58,18 +59,22 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque
const getTableList = async () => { const getTableList = async () => {
if (!api) return; if (!api) return;
try { try {
state.loading = true;
// 先把初始化参数和分页参数放到总参数里面 // 先把初始化参数和分页参数放到总参数里面
Object.assign(state.totalParam, initParam, isPageable ? pageParam.value : {}); Object.assign(state.totalParam, initParam, isPageable ? pageParam.value : {});
let { data } = await api({ ...state.searchInitParam, ...state.totalParam }); let { result } = await api({ ...state.searchInitParam, ...state.totalParam });
dataCallBack && (data = dataCallBack(data)); dataCallBack && (result = dataCallBack(result));
state.tableData = isPageable ? data.list : data;
state.tableData = isPageable ? result.content : result;
console.log(state.tableData, '---');
// 解构后台返回的分页数据 (如果有分页更新分页信息) // 解构后台返回的分页数据 (如果有分页更新分页信息)
if (isPageable) { if (isPageable) {
state.pageable.total = data.total; state.pageable.total = +result.page.totalElements;
} }
} catch (error) { } catch (error) {
requestError && requestError(error); requestError && requestError(error);
} }
state.loading = false;
}; };
/** /**
...@@ -99,7 +104,7 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque ...@@ -99,7 +104,7 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque
* @return void * @return void
* */ * */
const search = () => { const search = () => {
state.pageable.pageNum = 1; state.pageable.current = 1;
updatedTotalParam(); updatedTotalParam();
getTableList(); getTableList();
}; };
...@@ -109,7 +114,7 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque ...@@ -109,7 +114,7 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque
* @return void * @return void
* */ * */
const reset = () => { const reset = () => {
state.pageable.pageNum = 1; state.pageable.current = 1;
// 重置搜索表单的时,如果有默认搜索参数,则重置默认的搜索参数 // 重置搜索表单的时,如果有默认搜索参数,则重置默认的搜索参数
state.searchParam = { ...state.searchInitParam }; state.searchParam = { ...state.searchInitParam };
updatedTotalParam(); updatedTotalParam();
...@@ -122,8 +127,8 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque ...@@ -122,8 +127,8 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque
* @return void * @return void
* */ * */
const handleSizeChange = (val) => { const handleSizeChange = (val) => {
state.pageable.pageNum = 1; state.pageable.current = 1;
state.pageable.pageSize = val; state.pageable.size = val;
getTableList(); getTableList();
}; };
...@@ -133,7 +138,7 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque ...@@ -133,7 +138,7 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque
* @return void * @return void
* */ * */
const handleCurrentChange = (val) => { const handleCurrentChange = (val) => {
state.pageable.pageNum = val; state.pageable.current = val;
getTableList(); getTableList();
}; };
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
import Avatar from './components/Avatar.vue'; import Avatar from './components/Avatar.vue';
const userStore = useUserStore(); const userStore = useUserStore();
const username = computed(() => userStore.userInfo?.name); const username = computed(() => userStore.userInfo?.username);
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
......
...@@ -83,7 +83,7 @@ export function setupVxeTabele(app) { ...@@ -83,7 +83,7 @@ export function setupVxeTabele(app) {
resizable: true, // 列宽调整 resizable: true, // 列宽调整
}, },
checkboxConfig: { checkboxConfig: {
reserve: true, reserve: false,
}, },
rowConfig: { rowConfig: {
isCurrent: true, isCurrent: true,
......
...@@ -17,7 +17,7 @@ export const useGlobalStore = defineStore({ ...@@ -17,7 +17,7 @@ export const useGlobalStore = defineStore({
// 主题颜色 // 主题颜色
primary: DEFAULT_PRIMARY, primary: DEFAULT_PRIMARY,
// 深色模式 // 深色模式
isDark: true, isDark: false,
// 灰色模式 // 灰色模式
isGrey: false, isGrey: false,
// 色弱模式 // 色弱模式
......
...@@ -31,7 +31,7 @@ class RequestClient { ...@@ -31,7 +31,7 @@ class RequestClient {
config.cancel && axiosCanceler.addPending(config); config.cancel && axiosCanceler.addPending(config);
const { tenant } = useUserStore(); const { tenant } = useUserStore();
// 设置请求头 // 设置租户请求头
config.headers['tenantId'] = tenant?.id; config.headers['tenantId'] = tenant?.id;
if (config.method.toLocaleUpperCase() == 'GET') { if (config.method.toLocaleUpperCase() == 'GET') {
......
...@@ -10,18 +10,31 @@ ...@@ -10,18 +10,31 @@
<el-form ref="formRef" inline :model="form" :rules="rules" label-width="80px"> <el-form ref="formRef" inline :model="form" :rules="rules" label-width="80px">
<el-row :gutter="10"> <el-row :gutter="10">
<el-col :span="24"> <el-col :span="24">
<el-form-item class="w-full" label="名称" prop="name"> <el-form-item class="w-full" label="用户名称" prop="username">
<el-input v-model="form.name" placeholder="请输入名称" /> <el-input v-model="form.username" placeholder="请输入用户名称" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item class="w-full" label="账号" prop="code"> <el-form-item class="w-full" label="密码" prop="password">
<el-input v-model="form.code" placeholder="请输入账号" /> <el-input v-model="form.password" placeholder="请输入密码" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item class="w-full" label="角色" prop="role"> <el-form-item class="w-full" label="昵称" prop="nickName">
<el-input v-model="form.role" placeholder="请输入账号" /> <el-input v-model="form.nickName" placeholder="请输入昵称" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item class="w-full" label="手机号" prop="phone">
<el-input v-model="form.phone" placeholder="请输入手机号" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item class="w-full" label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio value="enable">启用</el-radio>
<el-radio value="disable">禁用</el-radio>
</el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
...@@ -36,35 +49,64 @@ ...@@ -36,35 +49,64 @@
<script setup> <script setup>
import { computed } from 'vue'; import { computed } from 'vue';
import { reactive, ref } from 'vue'; import { ref } from 'vue';
import { saveUser } from '@/api/user';
import { ElMessage } from 'element-plus';
const emits = defineEmits(['success']);
const formRef = ref(); const formRef = ref();
const showModal = ref(false); const showModal = ref(false);
const form = reactive({ const loading = ref(false);
name: '', const form = ref({
code: '', username: '',
role: '', nickName: '',
password: '',
phone: '',
status: 'enable',
});
const rules = ref({
username: { required: true, message: '请输入用户名称', trigger: 'blur' },
password: { required: true, message: '请输入密码', trigger: 'blur' },
}); });
const currentAccount = ref(undefined);
const currentAccount = ref(null);
const isEdit = computed(() => !!currentAccount.value); const isEdit = computed(() => !!currentAccount.value);
const modalTitle = computed(() => (isEdit.value ? '编辑账号' : '新增账号')); const modalTitle = computed(() => (isEdit.value ? '编辑账号' : '新增账号'));
const rules = reactive({ const submitForm = async () => {
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }], try {
code: [{ required: true, message: '账号不能为空', trigger: 'blur' }], await formRef.value.validate();
role: [{ required: true, message: '角色不能为空', trigger: 'blur' }], loading.value = true;
});
await saveUser(form.value);
const submitForm = () => {}; ElMessage({
type: 'success',
message: isEdit.value ? '修改成功!' : '添加成功!',
plain: true,
});
emits('success');
showModal.value = false;
} catch {}
loading.value = false;
};
const onHide = () => { const onHide = () => {
formRef.value.resetFields(); form.value = {
username: '',
nickName: '',
password: '',
phone: '',
status: 'enable',
};
formRef.value.clearValidate();
currentAccount.value = null; currentAccount.value = null;
showModal.value = false;
}; };
const openModal = (account) => { const openModal = (account) => {
showModal.value = true; account && (form.value = account);
currentAccount.value = account; currentAccount.value = account;
Object.assign(form, account); showModal.value = true;
}; };
defineExpose({ defineExpose({
......
<template> <template>
<div class="table-box"> <div class="table-box">
<ProTable :config="config" :data="data"> <ProTable ref="proTable" :config="config" :api="getUserPage">
<template #left_buttons> <template #left_buttons>
<el-button type="primary" plain :icon="Plus" @click="accountFormModalRef?.openModal()" <el-button type="primary" :icon="Plus" @click="accountFormModalRef?.openModal()"
>新增</el-button >新增</el-button
> >
<el-button type="danger" :icon="Delete" @click="handleDelete">删除</el-button>
</template> </template>
</ProTable> </ProTable>
<AccountFormModal ref="accountFormModalRef" /> <AccountFormModal ref="accountFormModalRef" @success="query" />
</div> </div>
</template> </template>
...@@ -17,22 +18,53 @@ ...@@ -17,22 +18,53 @@
import AccountFormModal from './components/AccountFormModal.vue'; import AccountFormModal from './components/AccountFormModal.vue';
import { Delete, Edit, Plus } from '@element-plus/icons-vue'; import { Delete, Edit, Plus } from '@element-plus/icons-vue';
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { ElButton } from 'element-plus'; import { ElButton, ElMessageBox, ElMessage, ElTag } from 'element-plus';
import { getUserPage, saveUser, deleteUsers } from '@/api/user';
import { onMounted } from 'vue';
const proTable = ref();
const accountFormModalRef = ref(); const accountFormModalRef = ref();
const config = reactive({ const config = reactive({
columns: [ columns: [
{ field: 'name', title: '名称', search: { el: 'input' } }, { type: 'checkbox', width: 50 },
{ field: 'username', minWidth: 200, title: '用户名称', search: { el: 'input' } },
{ {
field: 'code', field: 'nickName',
title: '账号', title: '昵称',
width: 160,
search: { el: 'input', props: { clearable: true } }, search: { el: 'input', props: { clearable: true } },
}, },
{ {
field: 'role', field: 'phone',
title: '角色', title: '手机号',
width: 160,
search: { el: 'input', props: { clearable: true } }, search: { el: 'input', props: { clearable: true } },
}, },
{
field: 'status',
title: '状态',
width: 100,
search: { el: 'select', props: { clearable: true } },
slots: {
default: ({ row }) => {
return (
<ElTag type={row.status == 'enable' ? 'primary' : 'danger'}>
{row.status == 'enable' ? '启用' : '禁用'}
</ElTag>
);
},
},
},
{
field: 'createTime',
title: '创建时间',
width: 170,
},
{
field: 'updateTime',
title: '更新时间',
width: 170,
},
{ {
field: 'action', field: 'action',
title: '操作', title: '操作',
...@@ -44,8 +76,8 @@ ...@@ -44,8 +76,8 @@
<ElButton link type="primary" icon={Edit} onClick={() => editAccount(row)}> <ElButton link type="primary" icon={Edit} onClick={() => editAccount(row)}>
编辑 编辑
</ElButton> </ElButton>
<ElButton link type="primary" icon={Delete} onClick={() => deleteAccount(row)}> <ElButton link type="primary" icon={Edit} onClick={() => handleDisable(row)}>
删除 {row.status == 'enable' ? '禁用' : '启用'}
</ElButton> </ElButton>
</> </>
); );
...@@ -55,17 +87,57 @@ ...@@ -55,17 +87,57 @@
], ],
}); });
const editAccount = (row) => { const handleDelete = async () => {
accountFormModalRef.value.openModal(JSON.parse(JSON.stringify(row))); const list = proTable.value.element.getCheckboxRecords();
if (list.length) {
await ElMessageBox.confirm('是否确认删除选中账户?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
});
const ids = list.map((v) => v.id).join(',');
await deleteUsers(ids);
ElMessage({
type: 'success',
message: '删除成功!',
plain: true,
});
query();
}
}; };
const deleteAccount = () => {}; const editAccount = (row) => accountFormModalRef.value.openModal(JSON.parse(JSON.stringify(row)));
const data = [ const handleDisable = async (row) => {
{ name: 'admin', code: 'admin', role: 'superadmin' }, await ElMessageBox.confirm(
{ name: 'account1', code: 'account1', role: 'user' }, `是否确认${row.status == 'enable' ? '禁用' : '启用'}该用户?`,
{ name: 'account2', code: 'account2', role: 'user' }, '提示',
{ name: 'account3', code: 'account3', role: 'user' }, {
]; confirmButtonText: '确认',
</script> cancelButtonText: '取消',
<style lang="scss" scoped> type: 'warning',
}
);
// 修改的状态
const status = row.status === 'enable' ? 'disable' : 'enable';
await saveUser({
...row,
status,
});
</style> row.status = status;
\ No newline at end of file ElMessage({
type: 'success',
message: `${status == 'enable' ? '启用' : '禁用'}成功!`,
plain: true,
});
};
const query = () => proTable.value?.search();
onMounted(() => {
query();
});
</script>
<style lang="scss" scoped></style>
<template>
<vxe-modal
v-model="showModal"
:title="modalTitle"
@hide="onHide"
width="500px"
show-maximize
show-footer
esc-closable
>
<el-form ref="formRef" :model="form" :rules="rules" inline label-width="80px">
<el-row :gutter="10">
<el-col :span="24">
<el-form-item class="w-full" label="角色名称" prop="roleName">
<el-input v-model="form.roleName" placeholder="请输入角色名称" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item class="w-full" label="角色编码" prop="roleCode">
<el-input v-model="form.roleCode" placeholder="请输入角色编码" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item class="w-full" label="角色描述" prop="roleDesc">
<el-input v-model="form.roleDesc" placeholder="请输入角色描述" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<el-button type="default" @click="showModal = false">取消</el-button>
<el-button :loading="loading" type="primary" @click="submitForm">提交</el-button>
</template>
</vxe-modal>
</template>
<script setup name="menuFormModal">
import { ref, computed } from 'vue';
import { saveRole } from '@/api/role';
import { ElMessage } from 'element-plus';
const emits = defineEmits(['success']);
const currentRole = ref(null);
const showModal = ref(false);
const formRef = ref(null);
const isEdit = computed(() => !!currentRole.value);
const modalTitle = computed(() => (isEdit.value ? '编辑角色' : '新增角色'));
const form = ref({
roleName: '',
roleCode: '',
roleDesc: '',
});
const rules = ref({
roleName: { required: true, message: '请输入角色名称', trigger: 'blur' },
roleCode: { required: true, message: '请输入角色编码', trigger: 'blur' },
});
const loading = ref(false);
const submitForm = async () => {
try {
await formRef.value.validate();
loading.value = true;
await saveRole(form.value);
emits('success');
ElMessage({
type: 'success',
message: isEdit.value ? '修改成功!' : '添加成功!',
plain: true,
});
showModal.value = false;
} catch {}
loading.value = false;
};
const onHide = () => {
form.value = {
roleName: '',
roleCode: '',
roleDesc: '',
};
formRef.value.clearValidate();
currentRole.value = null;
};
const openModal = (role) => {
role && (form.value = role);
currentRole.value = role;
showModal.value = true;
};
defineExpose({
openModal,
});
</script>
<template> <template>
<div class="card content-box"> <div class="table-box">
<span class="text"> 角色管理(待完善) 🍓🍇🍈🍉</span> <ProTable ref="proTable" :config="config" :api="getRolePage">
<template #left_buttons>
<el-button type="primary" :icon="Plus" @click="roleModalRef?.openModal()">新增</el-button>
<el-button type="danger" :icon="Delete" @click="onDelete">删除</el-button>
</template>
</ProTable>
<RoleFormModal ref="roleModalRef" @success="query" />
</div> </div>
</template> </template>
<script setup name="roleManage"></script> <script setup lang="jsx" name="roleManage">
import { ref, reactive, onMounted } from 'vue';
import { Plus, Delete, Edit, Setting } from '@element-plus/icons-vue';
import { getRolePage, deleteRoles } from '@/api/role';
import RoleFormModal from './components/RoleFormModal.vue';
import { ElMessageBox, ElMessage, ElButton } from 'element-plus';
const proTable = ref(null);
const roleModalRef = ref(null);
const config = reactive({
columns: [
{ type: 'checkbox', width: 50 },
{ field: 'roleName', title: '角色名称', search: { el: 'input' } },
{ field: 'roleCode', title: '角色编码', search: { el: 'input' } },
{ field: 'roleDesc', title: '角色描述', search: { el: 'input' } },
{
width: 280,
title: '操作',
slots: {
default: ({ row }) => (
<>
<ElButton type="primary" link icon={Edit} onClick={() => handleEdit(row)}>
编辑
</ElButton>
<ElButton type="primary" link icon={Setting}>
设置权限
</ElButton>
<ElButton type="primary" link icon={Setting}>
设置成员
</ElButton>
</>
),
},
},
],
});
const query = () => proTable.value?.search();
const handleEdit = (row) => roleModalRef.value.openModal(JSON.parse(JSON.stringify(row)));
const onDelete = async () => {
const list = proTable.value.element.getCheckboxRecords();
if (list.length > 0) {
await ElMessageBox.confirm('是否确认删除选中的数据?', '删除提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
});
const ids = list.map((v) => v.id).join(',');
await deleteRoles(ids);
ElMessage.success({
message: '删除成功',
plain: true,
});
query();
}
};
onMounted(() => {
query();
});
</script>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment