<script lang="ts" setup>
|
import type { TreeActionItem } from '@jnpf/ui';
|
import type { BasicColumn } from '@jnpf/ui/vxeTable';
|
|
import { computed, h, nextTick, onMounted, reactive, ref, toRefs, unref } from 'vue';
|
|
import { useMessage } from '@jnpf/hooks';
|
import { BasicLeftTree } from '@jnpf/ui';
|
import { useModal } from '@jnpf/ui/modal';
|
import { BasicVxeTable, useVxeTable } from '@jnpf/ui/vxeTable';
|
|
import { DeleteOutlined, FormOutlined } from '@ant-design/icons-vue';
|
import { Tag } from 'ant-design-vue';
|
|
import { delRole, getRoleList } from '#/api/permission/role';
|
import { addRoleRelation, getRoleRelationList, removeRoleRelation } from '#/api/permission/roleRelation';
|
import { $t } from '#/locales';
|
import { useOrganizeStore } from '#/store';
|
|
import Form from './Form.vue';
|
|
defineOptions({ name: 'PermissionRole' });
|
|
interface State {
|
activeKey: string;
|
treeKey: number;
|
treeData: any[];
|
treeLoading: boolean;
|
searchInfo: any;
|
keyword: string;
|
}
|
|
const state = reactive<State>({
|
activeKey: 'user',
|
treeKey: 0,
|
treeData: [],
|
treeLoading: false,
|
searchInfo: {
|
roleId: '',
|
},
|
keyword: '',
|
});
|
const { activeKey } = toRefs(state);
|
|
const organizeStore = useOrganizeStore();
|
const leftTreeRef = ref<Nullable<any>>(null);
|
const { createMessage, createConfirm } = useMessage();
|
const [registerForm, { openModal: openFormModal }] = useModal();
|
const userColumns: BasicColumn[] = [
|
{ title: '账号', dataIndex: 'account', width: 100 },
|
{ title: '姓名', dataIndex: 'realName', width: 100 },
|
{ title: '性别', dataIndex: 'gender', width: 90, align: 'center' },
|
{ title: '手机', dataIndex: 'mobilePhone', width: 120 },
|
{ title: '所属岗位', dataIndex: 'position', minWidth: 120 },
|
{ title: '状态', dataIndex: 'enabledMark', width: 70, align: 'center', slots: { default: 'enabledMark' } },
|
];
|
const organizeColumns: BasicColumn[] = [
|
{ title: '组织编码', dataIndex: 'enCode', width: 200 },
|
{ title: '组织名称', dataIndex: 'fullName', minWidth: 200 },
|
{ title: '组织说明', dataIndex: 'description', width: 200 },
|
];
|
const positionColumns: BasicColumn[] = [
|
{ title: '岗位编码', dataIndex: 'enCode', width: 200 },
|
{ title: '岗位名称', dataIndex: 'fullName', minWidth: 200 },
|
{ title: '岗位说明', dataIndex: 'description', width: 200 },
|
];
|
const formConfig: any = {
|
baseColProps: { span: 8 },
|
schemas: [
|
{
|
field: 'keyword',
|
label: $t('common.keyword'),
|
component: 'Input',
|
componentProps: {
|
placeholder: $t('common.enterKeyword'),
|
submitOnPressEnter: true,
|
},
|
},
|
],
|
};
|
const [registerTable, { reload, getSelectRowKeys, clearSelectedRowKeys, setTableData, setLoading }] = useVxeTable({
|
api: getRoleRelationList,
|
rowSelection: { type: 'checkbox' },
|
clickToRowSelect: false,
|
useSearchForm: true,
|
immediate: false,
|
formConfig,
|
});
|
const actionList: TreeActionItem[] = [
|
{
|
render: (node) => {
|
return (
|
!node.isSystem &&
|
h(FormOutlined, {
|
class: 'ml-[4px]',
|
title: '编辑',
|
onClick: (e) => {
|
e.stopPropagation();
|
addOrUpdateHandle(node.id);
|
},
|
})
|
);
|
},
|
},
|
{
|
render: (node) => {
|
return (
|
!node.isSystem &&
|
h(DeleteOutlined, {
|
class: 'ml-[4px]',
|
title: '删除',
|
onClick: (e) => {
|
e.stopPropagation();
|
handleDel(node.id);
|
},
|
})
|
);
|
},
|
},
|
];
|
const extraInfo: TreeActionItem = {
|
render: (node) => {
|
return (
|
node.isSystem &&
|
h(
|
Tag,
|
{
|
class: 'mr-0',
|
color: 'processing',
|
},
|
() => '系统',
|
)
|
);
|
},
|
};
|
|
const getTableBindValues = computed(() => {
|
const columns = state.activeKey == 'user' ? userColumns : state.activeKey == 'organize' ? organizeColumns : positionColumns;
|
return {
|
columns,
|
searchInfo: { ...state.searchInfo, type: state.activeKey },
|
};
|
});
|
const getTreeBindValue = computed(() => {
|
const message = state.activeKey == 'organize' ? '组织' : '岗位';
|
const tipMessage = state.activeKey === 'user' ? '' : `${message}角色用于给${message}附加权限`;
|
return {
|
showToolbar: false,
|
isCustomSearch: true,
|
treeData: state.treeData,
|
loading: state.treeLoading,
|
key: state.treeKey,
|
tipMessage,
|
actionList,
|
extraInfo,
|
onSelect: handleTreeSelect,
|
onSearch: handleTreeSearch,
|
};
|
});
|
|
function initTreeData(isReload = true) {
|
state.treeLoading = true;
|
getRoleList({ type: state.activeKey || 'user', keyword: state.keyword })
|
.then((res) => {
|
state.treeData = res.data.list || [];
|
state.treeLoading = false;
|
nextTick(() => {
|
if (isReload) {
|
state.searchInfo.roleId = state.treeData[0]?.id;
|
unref(leftTreeRef)?.setSelectedKeys([state.treeData[0]?.id]);
|
clearSelectedRowKeys();
|
setTimeout(() => {
|
reload();
|
}, 100);
|
}
|
});
|
})
|
.catch(() => {
|
state.treeLoading = false;
|
});
|
}
|
function onTabChange() {
|
unref(leftTreeRef)?.clearSearchValue();
|
setTableData([]);
|
setLoading(true);
|
initTreeData();
|
}
|
function addOrUpdateHandle(id = '') {
|
openFormModal(true, { id, type: state.activeKey });
|
}
|
function handleDel(id) {
|
createConfirm({
|
iconType: 'warning',
|
title: $t('common.tipTitle'),
|
content: $t('common.delTip'),
|
onOk: () => {
|
delRole(id).then((res) => {
|
createMessage.success(res.msg);
|
initTreeData();
|
organizeStore.$reset();
|
});
|
},
|
});
|
}
|
function handleTreeSelect(id) {
|
if (id == state.searchInfo.roleId) return;
|
state.searchInfo.roleId = id;
|
nextTick(() => {
|
clearSelectedRowKeys();
|
reload();
|
});
|
}
|
function handleAddRoleRelation(ids) {
|
addRoleRelation({ type: state.activeKey, roleId: state.searchInfo.roleId, ids }).then((res) => {
|
createMessage.success(res.msg);
|
reload();
|
});
|
}
|
function handleBatchRemove() {
|
const ids = getSelectRowKeys();
|
if (!ids.length) return createMessage.error($t('common.selectDataTip'));
|
createConfirm({
|
iconType: 'warning',
|
title: $t('common.tipTitle'),
|
content: '此操作将从当前角色中移除选中的组织,是否继续?',
|
onOk: () => {
|
removeRoleRelation({ type: state.activeKey, roleId: state.searchInfo.roleId, ids }).then((res) => {
|
createMessage.success(res.msg);
|
clearSelectedRowKeys();
|
reload();
|
});
|
},
|
});
|
}
|
function handleTreeSearch(value) {
|
state.keyword = value;
|
initTreeData(false);
|
}
|
|
onMounted(() => {
|
initTreeData();
|
});
|
</script>
|
<template>
|
<div class="relative flex h-full flex-col">
|
<a-alert show-icon type="warning" class="mb-[10px]">
|
<template #message>
|
组织、权限模块的详细说明介绍,请查阅使用帮助,<a class="link-text" target="_blank" href="https://usermanuals.jnpfsoft.com/#/docs/11007">点击查看</a>
|
</template>
|
</a-alert>
|
<div class="jnpf-content-wrapper">
|
<div class="jnpf-content-wrapper-left role-content-wrapper-left !w-[260px]">
|
<BasicLeftTree ref="leftTreeRef" v-bind="getTreeBindValue">
|
<template #headerTitle>
|
<a-tabs v-model:active-key="activeKey" class="jnpf-content-wrapper-tabs" :tab-bar-gutter="10" @change="onTabChange">
|
<a-tab-pane key="user" tab="用户角色" />
|
<a-tab-pane key="organize" tab="组织角色" />
|
<a-tab-pane key="position" tab="岗位角色" />
|
<template #rightExtra>
|
<i class="icon-ym icon-ym-btn-add cursor-pointer" @click="addOrUpdateHandle()"></i>
|
</template>
|
</a-tabs>
|
</template>
|
</BasicLeftTree>
|
</div>
|
<div class="jnpf-content-wrapper-center">
|
<div class="jnpf-content-wrapper-content">
|
<BasicVxeTable @register="registerTable" v-bind="getTableBindValues">
|
<template #tableTitle>
|
<jnpf-users-select
|
required
|
button-type="button"
|
button-show-type="primary"
|
:show-selected-list="false"
|
modal-title="添加用户"
|
multiple
|
@change="handleAddRoleRelation"
|
v-if="activeKey == 'user'" />
|
<jnpf-organize-select
|
required
|
button-type="button"
|
button-show-type="primary"
|
:show-selected-list="false"
|
modal-title="添加组织"
|
multiple
|
@change="handleAddRoleRelation"
|
v-else-if="activeKey == 'organize'" />
|
<jnpf-pos-select
|
required
|
button-type="button"
|
button-show-type="primary"
|
:show-selected-list="false"
|
modal-title="添加岗位"
|
multiple
|
@change="handleAddRoleRelation"
|
v-else />
|
<a-button type="link" @click="handleBatchRemove()"><i class="icon-ym icon-ym-add-cancel"></i>移除</a-button>
|
</template>
|
<template #enabledMark="{ record }">
|
<a-tag :color="record.enabledMark == 1 ? 'success' : record.enabledMark == 2 ? 'warning' : 'error'">
|
{{ record.enabledMark == 1 ? '启用' : record.enabledMark == 2 ? '锁定' : '禁用' }}
|
</a-tag>
|
</template>
|
</BasicVxeTable>
|
</div>
|
</div>
|
</div>
|
<Form @register="registerForm" @reload="initTreeData" />
|
</div>
|
</template>
|