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 @@
<!-- 分页组件 -->
<el-pagination
:background="true"
:current-page="pageable.pageNum"
:page-size="pageable.pageSize"
:current-page="pageable.current"
:page-size="pageable.size"
:page-sizes="[10, 25, 50, 100]"
:total="pageable.total"
:size="globalStore?.assemblySize ?? 'default'"
......
......@@ -15,7 +15,7 @@
<!-- 表格主体 -->
<div>
<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>
<slot name="left_buttons"></slot>
</template>
......@@ -80,13 +80,13 @@
},
data: {
type: Array,
default: () => [],
},
});
const xGrid = ref(null);
const {
tableData,
loading,
pageable,
gridConfig,
searchParam,
......
......@@ -2,14 +2,15 @@ import { reactive, toRefs, computed } from 'vue';
export function useProTable(api, initParam = {}, isPageable, dataCallBack, requestError) {
const state = reactive({
loading: false,
// 表格数据
tableData: [],
// 分页数据
pageable: {
// 当前页数
pageNum: 1,
current: 1,
// 每页显示条数
pageSize: 10,
size: 10,
// 总条数
total: 0,
},
......@@ -42,8 +43,8 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque
const pageParam = computed({
get: () => {
return {
pageNum: state.pageable.pageNum,
pageSize: state.pageable.pageSize,
current: state.pageable.current,
size: state.pageable.size,
};
},
set: (newVal) => {
......@@ -58,18 +59,22 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque
const getTableList = async () => {
if (!api) return;
try {
state.loading = true;
// 先把初始化参数和分页参数放到总参数里面
Object.assign(state.totalParam, initParam, isPageable ? pageParam.value : {});
let { data } = await api({ ...state.searchInitParam, ...state.totalParam });
dataCallBack && (data = dataCallBack(data));
state.tableData = isPageable ? data.list : data;
let { result } = await api({ ...state.searchInitParam, ...state.totalParam });
dataCallBack && (result = dataCallBack(result));
state.tableData = isPageable ? result.content : result;
console.log(state.tableData, '---');
// 解构后台返回的分页数据 (如果有分页更新分页信息)
if (isPageable) {
state.pageable.total = data.total;
state.pageable.total = +result.page.totalElements;
}
} catch (error) {
requestError && requestError(error);
}
state.loading = false;
};
/**
......@@ -99,7 +104,7 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque
* @return void
* */
const search = () => {
state.pageable.pageNum = 1;
state.pageable.current = 1;
updatedTotalParam();
getTableList();
};
......@@ -109,7 +114,7 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque
* @return void
* */
const reset = () => {
state.pageable.pageNum = 1;
state.pageable.current = 1;
// 重置搜索表单的时,如果有默认搜索参数,则重置默认的搜索参数
state.searchParam = { ...state.searchInitParam };
updatedTotalParam();
......@@ -122,8 +127,8 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque
* @return void
* */
const handleSizeChange = (val) => {
state.pageable.pageNum = 1;
state.pageable.pageSize = val;
state.pageable.current = 1;
state.pageable.size = val;
getTableList();
};
......@@ -133,7 +138,7 @@ export function useProTable(api, initParam = {}, isPageable, dataCallBack, reque
* @return void
* */
const handleCurrentChange = (val) => {
state.pageable.pageNum = val;
state.pageable.current = val;
getTableList();
};
......
......@@ -25,7 +25,7 @@
import Avatar from './components/Avatar.vue';
const userStore = useUserStore();
const username = computed(() => userStore.userInfo?.name);
const username = computed(() => userStore.userInfo?.username);
</script>
<style scoped lang="scss">
......
......@@ -83,7 +83,7 @@ export function setupVxeTabele(app) {
resizable: true, // 列宽调整
},
checkboxConfig: {
reserve: true,
reserve: false,
},
rowConfig: {
isCurrent: true,
......
......@@ -17,7 +17,7 @@ export const useGlobalStore = defineStore({
// 主题颜色
primary: DEFAULT_PRIMARY,
// 深色模式
isDark: true,
isDark: false,
// 灰色模式
isGrey: false,
// 色弱模式
......
......@@ -31,7 +31,7 @@ class RequestClient {
config.cancel && axiosCanceler.addPending(config);
const { tenant } = useUserStore();
// 设置请求头
// 设置租户请求头
config.headers['tenantId'] = tenant?.id;
if (config.method.toLocaleUpperCase() == 'GET') {
......
......@@ -10,18 +10,31 @@
<el-form ref="formRef" inline :model="form" :rules="rules" label-width="80px">
<el-row :gutter="10">
<el-col :span="24">
<el-form-item class="w-full" label="名称" prop="name">
<el-input v-model="form.name" placeholder="请输入名称" />
<el-form-item class="w-full" label="用户名称" prop="username">
<el-input v-model="form.username" placeholder="请输入用户名称" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item class="w-full" label="账号" prop="code">
<el-input v-model="form.code" placeholder="请输入账号" />
<el-form-item class="w-full" label="密码" prop="password">
<el-input v-model="form.password" placeholder="请输入密码" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item class="w-full" label="角色" prop="role">
<el-input v-model="form.role" placeholder="请输入账号" />
<el-form-item class="w-full" label="昵称" prop="nickName">
<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-col>
</el-row>
......@@ -36,35 +49,64 @@
<script setup>
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 showModal = ref(false);
const form = reactive({
name: '',
code: '',
role: '',
const loading = ref(false);
const form = ref({
username: '',
nickName: '',
password: '',
phone: '',
status: 'enable',
});
const currentAccount = ref(undefined);
const rules = ref({
username: { required: true, message: '请输入用户名称', trigger: 'blur' },
password: { required: true, message: '请输入密码', trigger: 'blur' },
});
const currentAccount = ref(null);
const isEdit = computed(() => !!currentAccount.value);
const modalTitle = computed(() => (isEdit.value ? '编辑账号' : '新增账号'));
const rules = reactive({
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
code: [{ required: true, message: '账号不能为空', trigger: 'blur' }],
role: [{ required: true, message: '角色不能为空', trigger: 'blur' }],
});
const submitForm = async () => {
try {
await formRef.value.validate();
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 = () => {
formRef.value.resetFields();
form.value = {
username: '',
nickName: '',
password: '',
phone: '',
status: 'enable',
};
formRef.value.clearValidate();
currentAccount.value = null;
showModal.value = false;
};
const openModal = (account) => {
showModal.value = true;
account && (form.value = account);
currentAccount.value = account;
Object.assign(form, account);
showModal.value = true;
};
defineExpose({
......
<template>
<div class="table-box">
<ProTable :config="config" :data="data">
<ProTable ref="proTable" :config="config" :api="getUserPage">
<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 type="danger" :icon="Delete" @click="handleDelete">删除</el-button>
</template>
</ProTable>
<AccountFormModal ref="accountFormModalRef" />
<AccountFormModal ref="accountFormModalRef" @success="query" />
</div>
</template>
......@@ -17,22 +18,53 @@
import AccountFormModal from './components/AccountFormModal.vue';
import { Delete, Edit, Plus } from '@element-plus/icons-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 config = reactive({
columns: [
{ field: 'name', title: '名称', search: { el: 'input' } },
{ type: 'checkbox', width: 50 },
{ field: 'username', minWidth: 200, title: '用户名称', search: { el: 'input' } },
{
field: 'code',
title: '账号',
field: 'nickName',
title: '昵称',
width: 160,
search: { el: 'input', props: { clearable: true } },
},
{
field: 'role',
title: '角色',
field: 'phone',
title: '手机号',
width: 160,
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',
title: '操作',
......@@ -44,8 +76,8 @@
<ElButton link type="primary" icon={Edit} onClick={() => editAccount(row)}>
编辑
</ElButton>
<ElButton link type="primary" icon={Delete} onClick={() => deleteAccount(row)}>
删除
<ElButton link type="primary" icon={Edit} onClick={() => handleDisable(row)}>
{row.status == 'enable' ? '禁用' : '启用'}
</ElButton>
</>
);
......@@ -55,17 +87,57 @@
],
});
const editAccount = (row) => {
accountFormModalRef.value.openModal(JSON.parse(JSON.stringify(row)));
const handleDelete = async () => {
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 data = [
{ name: 'admin', code: 'admin', role: 'superadmin' },
{ name: 'account1', code: 'account1', role: 'user' },
{ name: 'account2', code: 'account2', role: 'user' },
{ name: 'account3', code: 'account3', role: 'user' },
];
</script>
<style lang="scss" scoped>
const editAccount = (row) => accountFormModalRef.value.openModal(JSON.parse(JSON.stringify(row)));
const handleDisable = async (row) => {
await ElMessageBox.confirm(
`是否确认${row.status == 'enable' ? '禁用' : '启用'}该用户?`,
'提示',
{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}
);
// 修改的状态
const status = row.status === 'enable' ? 'disable' : 'enable';
await saveUser({
...row,
status,
});
</style>
\ No newline at end of file
row.status = status;
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>
<div class="card content-box">
<span class="text"> 角色管理(待完善) 🍓🍇🍈🍉</span>
<div class="table-box">
<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>
</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