This commit is contained in:
陈红丽 2024-07-10 15:24:27 +08:00
parent fcfaee7f43
commit c1249506fb
14 changed files with 365 additions and 385 deletions

View File

@ -58,9 +58,29 @@ export function roleDelete(roleId) {
/**
* @description:
*/
export function roleBatchDelete(roleId) {
export function roleBatchDelete(data) {
return http.request({
url: '/role/batchDelete/'+roleId,
url: '/role/batchDelete',
method: 'DELETE',
data
});
}
/**
* @description:
*/
export function getRoleMenuList(roleId) {
return http.request({
url: '/role/menu/list/'+roleId,
method: 'get',
});
}
/**
* @description:
*/
export function roleMenuSave(data:any) {
return http.request({
url: '/role/menu/save',
method: 'POST',
data,
});
}

View File

@ -103,6 +103,7 @@
<div class="flex justify-end s-table-pagination" v-if="pagination && isObject(pagination)">
<el-pagination
v-model:current-page="pagination.currentPage"
:page-sizes="pagination.pageSizes"
:page-size="pagination.pageSize"
:layout="pagination.layout"
:total="pagination.total"

View File

@ -7,6 +7,7 @@
<template v-for="(item, key) in parent.children" :key="item.key">
<el-menu-item v-if="!item.children" :index="item.key">
<template #title>
<icon :name="item.icon" :size="20" v-if="item.icon"/>
<span>{{ item.title }}</span>
</template>
</el-menu-item>

View File

@ -2,9 +2,9 @@ export default {
table: {
apiSetting: {
// 当前页的字段名
pageField: 'current',
pageField: 'pageNo',
// 每页数量字段名
sizeField: 'size',
sizeField: 'pageSize',
// 接口返回的数据字段名
listField: 'records',
// 接口返回总页数字段名

View File

@ -87,7 +87,7 @@
</div>
</el-form-item>
<el-form-item
v-if="formData.type == 0 && formData.target ==0"
v-if="formData.type == 0 && formData.target ==0 && formData.parentId!=0"
label="组件路径"
prop="component"
:rules="{ required: true, message: '请输入组件路径', trigger: 'blur' }"

View File

@ -1,202 +0,0 @@
<template>
<el-drawer
v-model="isDrawer"
:width="width"
placement="right"
:title="title"
@close="handleReset"
>
<el-form
:model="formParams"
:rules="rules"
ref="formRef"
label-placement="left"
:label-width="80"
>
<el-form-item label="角色编码" prop="roleCode">
<el-input
placeholder="请输入角色编码"
v-model="formParams.roleCode"
:disabled="formParams.roleId ? true : false"
/>
</el-form-item>
<el-form-item label="角色名称" prop="roleName">
<el-input placeholder="请输入角色名称" v-model="formParams.roleName" />
</el-form-item>
<el-form-item label="角色权限" prop="permissionIds">
<el-card shadow="hover">
<el-space>
<el-checkbox v-model:checked="isSpread" @change="packHandle">展开/收起</el-checkbox>
<el-checkbox v-model:checked="isAll" @change="handleCheckAll">全选/全不选</el-checkbox>
</el-space>
<el-divider />
<el-tree
ref="treeRef"
show-checkbox
node-key="key"
:data="props.permissionList"
@check="checkedTree"
/>
</el-card>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" placeholder="请输入备注" v-model="formParams.remark" />
</el-form-item>
</el-form>
<template #footer>
<el-space>
<el-button @click="handleReset">重置</el-button>
<el-button type="primary" :loading="subLoading" @click="formSubmit">提交</el-button>
</el-space>
</template>
</el-drawer>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import type { formParamsType } from './types';
import { getTreeValues } from '@/utils/helper/treeHelper';
const rules = {
roleCode: {
required: true,
message: '角色编码不能为空',
trigger: 'blur',
},
roleName: {
required: true,
message: '角色名称不能为空',
trigger: 'blur',
},
};
defineEmits(['change']);
const props = defineProps({
title: {
type: String,
default: '添加角色',
},
width: {
type: Number,
default: 450,
},
permissionList: {
type: Array,
},
});
const defaultValueRef = () => ({
roleId: null,
roleName: '',
roleCode: '',
remark: '',
permissions: [],
permissionKeys: [],
});
const message = ElMessage;
const checkedKeys = ref<number[]>([]);
const formRef: any = ref(null);
const isDrawer = ref(false);
const subLoading = ref(false);
const isSpread = ref(false);
const isAll = ref(false);
const treeRef = ref();
const expandedKeys = ref();
const formParams = ref<formParamsType>(defaultValueRef());
function treeNodeExpand(status) {
for (var i = 0; i < treeRef.value.store._getAllNodes().length; i++) {
treeRef.value.store._getAllNodes()[i].expanded = status;
}
}
function packHandle(value) {
if (value) {
treeNodeExpand(true);
expandedKeys.value = props?.permissionList?.map((item: any) => item.key as string) as [];
} else {
expandedKeys.value = [];
treeNodeExpand(false);
}
}
function handleCheckAll(value) {
if (!value) {
formParams.value.permissions = [];
treeRef.value!.setCheckedKeys([]);
} else {
formParams.value.permissions = getAllIds(
props?.permissionList as { key: number; children: [] }[],
);
const keys = getTreeValues(props.permissionList || [], 'key');
treeRef.value!.setCheckedKeys(keys);
}
}
function getAllIds(list: { key: number; children: [] }[] = [], ids: number[] = []) {
for (let item of list) {
!ids.includes(item.key) && ids.push(item.key);
if (item.children && item.children.length) getAllIds(item.children, ids);
}
return ids;
}
function checkedTree(_, checkedInfo) {
const keys = checkedInfo.checkedKeys;
const halfKeys = checkedInfo.halfCheckedKeys;
formParams.value.permissions = keys;
checkedKeys.value = keys;
formParams.value.permissionKeys = halfKeys;
}
function openDrawer(roleId?) {
if (roleId) {
formParams.value.roleId = roleId;
// id
getInfo();
return;
}
isDrawer.value = true;
}
function closeDrawer() {
isDrawer.value = false;
}
function formSubmit() {
formRef.value.validate((valid) => {
if (!valid) {
return message.error('请填写完整信息');
}
console.log(formParams.value);
// TOOD
message.success('操作成功');
closeDrawer();
});
}
function handleReset() {
formRef.value.resetFields();
formParams.value = Object.assign(formParams.value, defaultValueRef());
treeRef.value!.setCheckedKeys([]);
}
function getInfo() {
//
// formParams.value = res;
isDrawer.value = true;
}
onMounted(() => {});
defineExpose({
openDrawer,
closeDrawer,
});
</script>

View File

@ -0,0 +1,132 @@
<template>
<el-dialog
v-model="props.visible"
title="权限设置"
:append-to-body="true"
width="500"
:close-on-click-modal="false"
modal-class="roleMenuDialog"
:before-close="dialogClose"
>
<el-form
class="ls-form"
ref="formRef"
label-width="60px"
>
<el-form-item label="权限" prop="menus">
<div>
<el-checkbox label="展开/折叠" @change="handleExpand"/>
<el-checkbox label="全选/不全选" @change="handleSelectAll"/>
<div>
<el-tree
ref="treeRef"
:data="menuTree"
:props="{
label: 'name',
children: 'children',
}"
node-key="id"
:default-expand-all="isExpand"
show-checkbox
/>
</div>
</div>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogClose">取消</el-button>
<el-button :loading="subLoading" type="primary" @click="submit">
确定
</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import type {CheckboxValueType, ElTree, FormInstance} from "element-plus";
import {getRoleMenuList,roleMenuSave} from "@/api/system/role";
import {message,buildTree} from "@/utils/auth";
import {nextTick, onMounted, ref, shallowRef} from "vue";
import {useLockFn} from "@/utils/useLockFn";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false
},
roleId: {
type: Number,
required: true,
default: 0
}
});
const emit = defineEmits(["success", "update:visible"]);
const treeRef = shallowRef<InstanceType<typeof ElTree>>();
const formRef = shallowRef<FormInstance>();
const isExpand = ref(false);
const menuArray = ref<any[]>([]);
const menuTree = ref<any[]>([]);
//
const getDeptAllCheckedKeys = () => {
const checkedKeys = treeRef.value?.getCheckedKeys();
return checkedKeys;
};
const handleExpand = (check: CheckboxValueType) => {
const treeList = menuTree.value;
for (let i = 0; i < treeList.length; i++) {
treeRef.value.store.nodesMap[treeList[i].id].expanded = check;
}
};
const handleSelectAll = (check: CheckboxValueType) => {
if (check) {
treeRef.value?.setCheckedKeys(menuArray.value.map((item) => item.id));
} else {
treeRef.value?.setCheckedKeys([]);
}
};
const handleSubmit = async () => {
await formRef.value?.validate();
const menuIds = getDeptAllCheckedKeys()!;
await roleMenuSave({menuIds,roleId:props.roleId});
message("操作成功");
emit("update:visible", false);
emit("success");
};
const { isLock:subLoading,lockFn: submit } = useLockFn(handleSubmit);
const dialogClose = () => {
emit("update:visible", false);
};
const setFormData = async () => {
const data = await getRoleMenuList(props.roleId);
menuTree.value = buildTree(data);
menuArray.value =data;
nextTick(()=>{
let ids = [];
menuArray.value.map(item=>{
if(item.checked){
ids.push(item.id)
}
})
treeRef.value?.setCheckedKeys(ids,true, false);
})
};
onMounted(() => {
setFormData();
});
</script>
<style lang="scss">
.roleMenuDialog .el-dialog__body {
max-height:600px;
overflow: auto
}
</style>

View File

@ -3,17 +3,24 @@ import { ElTag } from 'element-plus';
export const columns = [
{
label: 'id',
prop: 'id',
type: 'selection',
},
{
label: '角色名称',
prop: 'name',
},
{
label: '角色编码',
prop: 'code',
},
{
label: '说明',
prop: 'note',
},
{
label: '创建人',
prop: 'createUser',
},
{
label: '创建时间',
prop: 'createTime',

View File

@ -0,0 +1,120 @@
<template>
<el-dialog
v-model="props.visible"
:title="props.roleId?'编辑':'新增'"
:append-to-body="true"
width="500"
:close-on-click-modal="false"
:before-close="dialogClose"
>
<el-form
class="ls-form"
ref="formRef"
:model="formData"
label-width="60px"
>
<el-form-item
label="名称"
prop="name"
:rules="{ required: true, message: '请输入名称', trigger: 'blur' }"
>
<el-input
class="ls-input"
v-model="formData.name"
placeholder="请输入名称"
clearable
/>
</el-form-item>
<el-form-item
label="编码"
prop="code"
:rules="{ required: true, message: '请输入编码', trigger: 'blur' }"
>
<el-input
class="ls-input"
v-model="formData.code"
placeholder="请输入编码"
clearable
/>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="formData.sort"/>
</el-form-item>
<el-form-item label="备注" prop="note">
<el-input v-model="formData.note" type="textarea" placeholder="请输入备注" clearable />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogClose">取消</el-button>
<el-button :loading="subLoading" type="primary" @click="submit">
确定
</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import type {FormInstance} from "element-plus";
import {getRoleDetail,roleAdd,roleUpdate} from "@/api/system/role";
import {onMounted, reactive, shallowRef} from "vue";
import {message} from "@/utils/auth";
import {useLockFn} from "@/utils/useLockFn";
const emit = defineEmits(["success", "update:visible"]);
const formRef = shallowRef<FormInstance>();
const formData = reactive({
id: "",
name: "",
code: "",
sort: 0,
note:'',
menus: []
});
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false
},
roleId: {
type: Number,
required: true,
default: 0
}
});
const handleSubmit = async () => {
await formRef.value?.validate();
const params = {...formData, menuIds: formData.menus.join()};
props.roleId ? await roleUpdate(params) : await roleAdd(params);
message("操作成功");
emit("update:visible", false);
emit("success");
};
const dialogClose = () => {
emit("update:visible", false);
};
const { isLock:subLoading,lockFn: submit } = useLockFn(handleSubmit);
const setFormData = async () => {
const data = await getRoleDetail(props.roleId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key];
}
}
};
onMounted(() => {
if (props.roleId) {
setFormData();
}
});
</script>

View File

@ -7,10 +7,10 @@
:row-key="(row) => row.id"
ref="tableRef"
:actionColumn="actionColumn"
@checked-row-change="onCheckedRow"
@selection-change="onSelectionChange"
>
<template #tableTitle>
<el-button type="primary" @click="openCreateDrawer">
<el-button type="primary" @click="handleAdd">
<template #icon>
<el-icon class="el-input__icon">
<PlusOutlined />
@ -18,6 +18,14 @@
</template>
添加角色
</el-button>
<el-button type="danger" @click="handleDelete()" :disabled="!selectionData.length">
<template #icon>
<el-icon class="el-input__icon">
<Delete />
</el-icon>
</template>
删除
</el-button>
</template>
<template #action>
@ -26,79 +34,42 @@
</BasicTable>
</el-card>
<el-dialog v-model="showModal" draggable :title="editRoleTitle" :width="550">
<div class="py-3 menu-list">
<el-tree
ref="treeRef"
show-checkbox
node-key="key"
:data="treeData"
style="max-height: 950px; overflow: hidden"
@update:checked-keys="checkedTree"
@update:expanded-keys="onExpandedKeys"
/>
</div>
<template #footer>
<el-space>
<el-button plain icon-placement="left" @click="packHandle">
全部{{ expandAllStatus ? '收起' : '展开' }}
<el-icon class="el-icon--right" v-if="expandAllStatus"><arrow-up /> </el-icon>
<el-icon class="el-icon--right" v-else><arrow-down /></el-icon>
</el-button>
<el-button plain icon-placement="left" @click="checkedAllHandle">
全部{{ checkedAll ? '取消' : '选择' }}
</el-button>
<el-button type="primary" :loading="formBtnLoading" @click="confirmForm"
>保存提交</el-button
>
</el-space>
</template>
</el-dialog>
<CreateDrawer
ref="createDrawerRef"
:title="drawerTitle"
:permissionList="treeData"
@change="reloadTable"
/>
<editDialog
v-if="editVisible"
:roleId="roleId"
v-model:visible="editVisible"
@success="reloadTable"
>
</editDialog>
<authDialog
v-if="authVisible"
:roleId="roleId"
v-model:visible="authVisible"
@success="reloadTable"
>
</authDialog>
</PageWrapper>
</template>
<script lang="ts" setup>
import { reactive, ref, unref, h, onMounted } from 'vue';
import { reactive, ref, h,nextTick,defineAsyncComponent } from 'vue';
import { ElMessage } from 'element-plus';
import { BasicTable, TableAction } from '@/components/Table';
import { getRoleList } from '@/api/system/role';
import { getMenuList } from '@/api/system/menu';
import { getRoleList,roleDelete,roleBatchDelete } from '@/api/system/role';
import { columns } from './columns';
import { PlusOutlined } from '@vicons/antd';
import { getTreeAll } from '@/utils';
import { useRouter } from 'vue-router';
import { ArrowDown, ArrowUp } from '@element-plus/icons-vue';
import CreateDrawer from './CreateDrawer.vue';
const router = useRouter();
const formRef: any = ref(null);
import {message,confirm} from "@/utils/auth";
const editDialog = defineAsyncComponent(() =>
import('./edit.vue')
)
const authDialog = defineAsyncComponent(() =>
import('./auth.vue')
)
const roleId =ref(0)
const editVisible=ref(false)
const authVisible=ref(false)
const selectionData = ref([])
const tableRef = ref();
const treeRef = ref();
const showModal = ref(false);
const expandAllStatus = ref(false);
const formBtnLoading = ref(false);
const checkedAll = ref(false);
const editRoleTitle = ref('');
const treeData = ref([]);
const expandedKeys = ref([]);
const checkedKeys = ref(['console', 'step-form']);
const createDrawerRef = ref();
const drawerTitle = ref('添加角色');
const params = reactive({
pageSize: 20,
name: '',
});
const actionColumn = reactive({
width: 250,
@ -111,31 +82,34 @@
actions: [
{
label: '分配权限',
onClick: handleMenuAuth.bind(null, record),
type: 'warning',
onClick: handleAuth.bind(null, record),
// isShow auth
ifShow: () => {
return true;
},
// :
auth: ['basic_list'],
// auth: ['basic_list'],
},
{
label: '编辑',
type: 'warning',
onClick: handleEdit.bind(null, record),
ifShow: () => {
return true;
},
auth: ['basic_list'],
// auth: ['basic_list'],
},
{
label: '删除',
type: 'danger',
onClick: handleDelete.bind(null, record),
// isShow auth
ifShow: () => {
return true;
},
// :
auth: ['basic_list'],
// auth: ['basic_list'],
},
],
});
@ -144,105 +118,45 @@
const loadDataTable = async (res: any) => {
let _params = {
...unref(params),
...res,
};
return await getRoleList(_params);
};
function openCreateDrawer() {
drawerTitle.value = '添加角色';
const { openDrawer } = createDrawerRef.value;
openDrawer();
}
function onCheckedRow(rowKeys: any[]) {
console.log(rowKeys);
}
function reloadTable() {
tableRef.value.reload();
}
function confirmForm(e: any) {
e.preventDefault();
formBtnLoading.value = true;
formRef.value.validate((errors) => {
if (!errors) {
ElMessage.success('新建成功');
setTimeout(() => {
showModal.value = false;
reloadTable();
});
} else {
ElMessage.error('请填写完整信息');
}
formBtnLoading.value = false;
});
}
const handleAdd = async () => {
roleId.value=0
await nextTick();
editVisible.value=true
};
function handleEdit(record: Recordable) {
console.log('点击了编辑', record);
drawerTitle.value = '编辑角色';
const { openDrawer } = createDrawerRef.value;
openDrawer(record.roleId);
}
const handleEdit = async (record: Recordable) => {
roleId.value=record.row.id
await nextTick();
editVisible.value=true
};
const handleAuth = async (record: Recordable) => {
roleId.value=record.row.id
await nextTick();
authVisible.value=true
};
function handleDelete(record: Recordable) {
console.log('点击了删除', record);
ElMessage.info('点击了删除');
}
function handleMenuAuth(record: Recordable) {
editRoleTitle.value = `分配 ${record.row.name} 权限`;
checkedKeys.value = record.row.menu_keys;
showModal.value = true;
}
function checkedTree(keys) {
checkedKeys.value = [checkedKeys.value, ...keys];
}
function onExpandedKeys(keys) {
expandedKeys.value = keys;
}
async function packHandle() {
if (expandAllStatus.value) {
treeNodeExpand(false);
expandAllStatus.value = false;
} else {
treeNodeExpand(true);
expandAllStatus.value = true;
async function handleDelete(record: Recordable) {
let ids = []
if(!record){
ids = selectionData.value.map(({id}) => id);
}
await confirm('确定要删除?');
record? await roleDelete(record.row.id):await roleBatchDelete(ids);
message("删除成功");
reloadTable()
}
function checkedAllHandle() {
if (!checkedAll.value) {
checkedKeys.value = getTreeAll(treeData.value);
treeRef.value!.setCheckedKeys(getTreeAll(treeData.value));
checkedAll.value = true;
} else {
checkedKeys.value = [];
checkedAll.value = false;
treeRef.value!.setCheckedKeys([]);
}
function onSelectionChange(value){
selectionData.value = value
}
function treeNodeExpand(status) {
for (var i = 0; i < treeRef.value.store._getAllNodes().length; i++) {
treeRef.value.store._getAllNodes()[i].expanded = status;
}
}
onMounted(async () => {
const treeMenuList = await getMenuList();
treeMenuList.forEach((item) => {
item.expanded = false;
});
expandedKeys.value = treeMenuList.map((item) => item.key);
treeData.value = treeMenuList;
});
</script>
<style lang="scss" scoped></style>

View File

@ -1,8 +0,0 @@
export interface formParamsType {
roleId?: number | null;
roleName: string;
roleCode: string;
remark: string;
permissions: number[];
permissionKeys: number[];
}

View File

@ -94,7 +94,6 @@
<el-form-item label="备注" prop="note" class="flex-1">
<el-input v-model="formData.note" type="textarea" placeholder="请输入备注" clearable />
</el-form-item>
</div>
<el-form-item label="头像" prop="images">
<BasicUpload :action="`${uploadUrl}/api/upload/uploadFile`" :list="formData.avatar?[{name:formData.avatarName,url:formData.avatar}]:[]" :headers="uploadHeaders"
@ -116,12 +115,12 @@
import { getUserDetail, userAdd, userUpdate } from '@/api/system/user';
import { BasicUpload } from '@/components/Upload';
import chinaArea from '@/components/ChinaArea/index.vue';
import { computed, onMounted, reactive, shallowRef, ref, unref } from "vue";
import { onMounted, reactive, shallowRef } from "vue";
import { getRoleAllList } from '@/api/system/role';
import { getDeptList } from '@/api/system/dept';
import { getLevelAllList } from '@/api/system/level';
import { getPositionAllList } from '@/api/system/position';
import {buildTree, message } from "@/utils/auth";
import {buildTree } from "@/utils/auth";
import { FormInstance } from "element-plus";
const formRef = shallowRef<FormInstance>();

View File

@ -97,23 +97,18 @@
const upload = ref<UploadInstance>();
const exportLoading=ref(false)
const editDialog = defineAsyncComponent(() =>
import('./edit.vue')
)
import('./edit.vue'))
const uploadHeaders = reactive({
authorization:useUserStore().getToken
});
const formParams = reactive({
username: '',
realname: '',
mobile: '',
role:'',
email: '',
status:'',
});
const params = ref({
pageSize: 20,
name: '',
});
const actionColumn = reactive({
width: 250,
@ -159,7 +154,7 @@ const uploadHeaders = reactive({
});
const loadDataTable = async (res) => {
const result = await getUserList({ ...formParams, ...params.value, ...res });
const result = await getUserList({ ...formParams, ...res });
tableData.value = result.records;
return result;
};
@ -181,7 +176,7 @@ const uploadHeaders = reactive({
async function handleDelete(record: Recordable) {
let ids = ''
let ids = []
if(!record){
ids = selectionData.value.map(({id}) => id);
}

View File

@ -13,7 +13,7 @@ export const loadSelectData = async(res)=> {
}
export const schemas: FormSchema[] = [
{
field: 'username',
field: 'realname',
component: 'Input',
label: '用户名',
componentProps: {
@ -36,6 +36,7 @@ export const schemas: FormSchema[] = [
componentProps: {
placeholder: '请选择角色',
block:true,
multiple:true,
request: loadSelectData,
onChange: (e: any) => {
console.log(e);