<script lang="ts" setup>
|
import type { TreeActionItem, TreeActionType } from '@jnpf/ui';
|
import type { ActionItem, BasicColumn, FormProps } from '@jnpf/ui/vxeTable';
|
|
import { computed, h, nextTick, onMounted, reactive, ref, unref } from 'vue';
|
import { useRouter } from 'vue-router';
|
|
import { useMessage } from '@jnpf/hooks';
|
import { BasicLeftTree } from '@jnpf/ui';
|
import { useModal } from '@jnpf/ui/modal';
|
import { usePopup } from '@jnpf/ui/popup';
|
import { BasicVxeTable, TableAction, useVxeTable } from '@jnpf/ui/vxeTable';
|
|
import { StorageManager } from '@vben-core/shared/cache';
|
|
import { DeleteOutlined, DownOutlined, FormOutlined } from '@ant-design/icons-vue';
|
|
import { addGroupUser, delGroup, getGroupList, removeGroupUser } from '#/api/permission/group';
|
import { batchDelete, batchSetUserPosition, batchUpdateState, delUser, getUserList, getUserPosition, setUserPosition, unlockUser } from '#/api/permission/user';
|
import { $t } from '#/locales';
|
import { useBaseStore, useOrganizeStore } from '#/store';
|
import ExportModal from '#/views/permission/common/components/ExportModal.vue';
|
import ImportModal from '#/views/permission/common/components/ImportModal.vue';
|
|
import Form from './Form.vue';
|
import GroupForm from './GroupForm.vue';
|
import PermissionPopup from './Permission.vue';
|
import ResetPassword from './ResetPassword.vue';
|
import SocialsBind from './SocialsBind.vue';
|
import WorkHandoverModal from './WorkHandoverModal.vue';
|
|
defineOptions({ name: 'PermissionUser' });
|
|
interface State {
|
treeData: any[];
|
treeLoading: boolean;
|
currentUserId: string;
|
currentPosId: any[];
|
keyword: string;
|
}
|
|
const { createMessage, createConfirm } = useMessage();
|
const baseStore = useBaseStore();
|
const router = useRouter();
|
|
const organizeStore = useOrganizeStore();
|
const ls = new StorageManager();
|
const leftTreeRef = ref<Nullable<TreeActionType>>(null);
|
const state = reactive<State>({
|
treeData: [],
|
treeLoading: false,
|
currentUserId: '',
|
currentPosId: [],
|
keyword: '',
|
});
|
const searchInfo = reactive({
|
groupId: '',
|
});
|
const postSelectRef = ref<any>('');
|
const batchPostSelectRef = ref<any>('');
|
const [registerPsdModal, { openModal: openPsdModal }] = useModal();
|
const [registerExportModal, { openModal: openExportModal }] = useModal();
|
const [registerImportModal, { openModal: openImportModal }] = useModal();
|
const [registerWorkHandoverModal, { openModal: openWorkHandoverModal }] = useModal();
|
const [registerForm, { openPopup: openFormPopup }] = usePopup();
|
const [registerSocialsBind, { openPopup: openSocialsBindPopup }] = usePopup();
|
const [registerPermission, { openPopup: openPermissionPopup }] = usePopup();
|
const [registerGroupForm, { openModal: openGroupFormModal }] = useModal();
|
const columns: 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: 'creatorTime', width: 150, format: 'date|YYYY-MM-DD HH:mm:ss' },
|
{ title: '排序', dataIndex: 'sortCode', width: 70, align: 'center' },
|
{ title: '状态', dataIndex: 'enabledMark', width: 70, align: 'center', slots: { default: 'enabledMark' } },
|
];
|
const actionList: TreeActionItem[] = [
|
{
|
render: (node) => {
|
return (
|
node.id &&
|
h(FormOutlined, {
|
class: 'ml-[4px]',
|
title: '编辑',
|
onClick: (e) => {
|
e.stopPropagation();
|
addOrUpdateGroupHandle(node.id);
|
},
|
})
|
);
|
},
|
},
|
{
|
render: (node) => {
|
return (
|
node.id &&
|
h(DeleteOutlined, {
|
class: 'ml-[4px]',
|
title: '删除',
|
onClick: (e) => {
|
e.stopPropagation();
|
handleDelGroup(node.id);
|
},
|
})
|
);
|
},
|
},
|
];
|
const [registerTable, { reload, getForm, getSelectRowKeys, clearSelectedRowKeys, getFetchParams }] = useVxeTable({
|
api: getUserList,
|
columns,
|
useSearchForm: true,
|
formConfig: getFormConfig(),
|
actionColumn: {
|
width: 150,
|
title: '操作',
|
dataIndex: 'action',
|
},
|
rowSelection: { type: 'checkbox' },
|
clickToRowSelect: false,
|
});
|
|
const getSelectRowLen = computed(() => !!getSelectRowKeys().length);
|
const getTreeBindValue = computed(() => ({
|
showToolbar: false,
|
isCustomSearch: true,
|
treeData: state.treeData,
|
loading: state.treeLoading,
|
actionList,
|
onSelect: handleTreeSelect,
|
onSearch: handleTreeSearch,
|
}));
|
|
function getFormConfig(): Partial<FormProps> {
|
return {
|
schemas: [
|
{
|
field: 'keyword',
|
label: $t('common.keyword'),
|
component: 'Input',
|
componentProps: {
|
placeholder: $t('common.enterKeyword'),
|
submitOnPressEnter: true,
|
},
|
},
|
{
|
field: 'gender',
|
label: '性别',
|
component: 'Select',
|
componentProps: {
|
fieldNames: { value: 'enCode' },
|
},
|
},
|
{
|
field: 'enabledMark',
|
label: '状态',
|
component: 'Select',
|
componentProps: {
|
options: [
|
{ fullName: '启用', id: 1 },
|
{ fullName: '禁用', id: 0 },
|
{ fullName: '锁定', id: 2 },
|
],
|
},
|
},
|
],
|
};
|
}
|
function getTableActions(record): ActionItem[] {
|
return [
|
{
|
label: $t('common.editText'),
|
onClick: addOrUpdateHandle.bind(null, record.id),
|
},
|
{
|
label: $t('common.delText'),
|
color: 'error',
|
modelConfirm: {
|
onOk: handleDelete.bind(null, record.id),
|
},
|
},
|
];
|
}
|
function getDropDownActions(record): ActionItem[] {
|
return [
|
{
|
label: '重置密码',
|
onClick: handleResetPwd.bind(null, record.id, record.account),
|
},
|
{
|
label: '解除锁定',
|
ifShow: record.enabledMark === 2,
|
modelConfirm: {
|
title: '解除锁定',
|
content: '此操作将解除该账户锁定, 是否继续?',
|
onOk: handleUnlock.bind(null, record.id),
|
},
|
},
|
{
|
label: '社交账号',
|
ifShow: !!ls.getItem('useSocials'),
|
onClick: handleSocialsBind.bind(null, record.id),
|
},
|
{
|
disabled: record.enabledMark == 1 || record.enabledMark == 2,
|
label: '工作交接',
|
onClick: handleWorkHandover.bind(null, record),
|
},
|
{
|
label: '查看权限',
|
onClick: handlePermission.bind(null, record.id, record.realName),
|
},
|
{
|
label: '调整岗位',
|
onClick: handleAdjustPosition.bind(null, record.id),
|
},
|
];
|
}
|
function addOrUpdateHandle(id = '') {
|
openFormPopup(true, { id, groupId: searchInfo.groupId });
|
}
|
function handleDelete(id) {
|
delUser(id).then((res) => {
|
createMessage.success(res.msg);
|
reload();
|
});
|
}
|
function handleResetPwd(id, account) {
|
openPsdModal(true, { id, account });
|
}
|
function handleSocialsBind(id) {
|
openSocialsBindPopup(true, { id });
|
}
|
function handleWorkHandover(record) {
|
openWorkHandoverModal(true, { userInfo: record });
|
}
|
function handlePermission(id, fullName) {
|
openPermissionPopup(true, { id, fullName, objectType: 'user' });
|
}
|
function handleUnlock(id) {
|
unlockUser(id).then((res) => {
|
createMessage.success(res.msg);
|
reload();
|
});
|
}
|
function handleExport() {
|
const listQuery = {
|
...getFetchParams(),
|
keyword: getFetchParams().keyword || '',
|
};
|
openExportModal(true, { listQuery });
|
}
|
function handleImport() {
|
openImportModal(true, {});
|
}
|
function handleSync({ key }) {
|
router.push(`/integrationCenter/${key === 0 ? 'dingTalk' : 'weCom'}`);
|
}
|
function handleAdd({ key }) {
|
if (key === 0) addOrUpdateHandle('');
|
}
|
function handleBatchUpdateState(enabledMark) {
|
const ids = getSelectRowKeys();
|
if (!ids.length) return createMessage.error($t('common.selectDataTip'));
|
createConfirm({
|
iconType: 'warning',
|
title: $t('common.tipTitle'),
|
content: `您确定要${enabledMark == 1 ? '启用' : enabledMark == 2 ? '锁定' : '禁用'}这些数据吗, 是否继续?`,
|
onOk: () => {
|
batchUpdateState({ ids, enabledMark }).then((res) => {
|
createMessage.success(res.msg);
|
clearSelectedRowKeys();
|
reload();
|
});
|
},
|
});
|
}
|
function handleBatchDel() {
|
const ids = getSelectRowKeys();
|
if (!ids.length) return createMessage.error($t('common.selectDataTip'));
|
createConfirm({
|
iconType: 'warning',
|
title: $t('common.tipTitle'),
|
content: $t('common.batchDelTip'),
|
onOk: () => {
|
batchDelete({ ids }).then((res) => {
|
createMessage.success(res.msg);
|
clearSelectedRowKeys();
|
reload();
|
});
|
},
|
});
|
}
|
function handleBatchRemove() {
|
const ids = getSelectRowKeys();
|
if (!ids.length) return createMessage.error($t('common.selectDataTip'));
|
createConfirm({
|
iconType: 'warning',
|
title: $t('common.tipTitle'),
|
content: '此操作将从当前角色中移除选中的组织,是否继续?',
|
onOk: () => {
|
removeGroupUser(searchInfo.groupId, { ids }).then((res) => {
|
createMessage.success(res.msg);
|
clearSelectedRowKeys();
|
reload();
|
});
|
},
|
});
|
}
|
function handleTreeSelect(id) {
|
if (searchInfo.groupId === id) return;
|
searchInfo.groupId = id === '0' ? '' : id;
|
getForm().resetFields();
|
}
|
function addOrUpdateGroupHandle(id = '') {
|
openGroupFormModal(true, { id });
|
}
|
function handleDelGroup(id) {
|
createConfirm({
|
iconType: 'warning',
|
title: $t('common.tipTitle'),
|
content: $t('common.delTip'),
|
onOk: () => {
|
delGroup(id).then((res) => {
|
createMessage.success(res.msg);
|
organizeStore.$reset();
|
searchInfo.groupId = '';
|
initGroupList();
|
reload({ page: 1 });
|
});
|
},
|
});
|
}
|
function initGroupList(isReload = true) {
|
state.treeLoading = true;
|
getGroupList({ keyword: state.keyword })
|
.then((res) => {
|
state.treeData = [...(state.keyword ? [] : [{ fullName: '全部用户', id: '' }]), ...(res.data.list || [])];
|
state.treeLoading = false;
|
nextTick(() => {
|
isReload && unref(leftTreeRef)?.setSelectedKeys([state.treeData[0]?.id]);
|
});
|
})
|
.catch(() => {
|
state.treeLoading = false;
|
});
|
}
|
async function initOptions() {
|
const sexRes = await baseStore.getDictionaryData('sex');
|
getForm().updateSchema({ field: 'gender', componentProps: { options: sexRes } });
|
}
|
function handleAddGroupUser(ids) {
|
addGroupUser(searchInfo.groupId, { ids }).then((res) => {
|
createMessage.success(res.msg);
|
reload();
|
});
|
}
|
function handleBatchAdjustPosition() {
|
unref(batchPostSelectRef)?.openSelectModal();
|
}
|
function handleAdjustPosition(id) {
|
state.currentUserId = id;
|
getUserPosition(id).then((res) => {
|
const data = res.data || [];
|
state.currentPosId = data.flatMap((o) => o.id);
|
nextTick(() => unref(postSelectRef)?.openSelectModal());
|
});
|
}
|
function onAdjustPositionChange(ids) {
|
setUserPosition({ id: state.currentUserId, ids }).then((res) => {
|
reload();
|
createMessage.success(res.msg);
|
});
|
}
|
function onBatchAdjustPositionChange(ids) {
|
const userIds = getSelectRowKeys();
|
if (!userIds.length) return createMessage.error($t('common.selectDataTip'));
|
batchSetUserPosition({ userIds, ids }).then((res) => {
|
reload();
|
clearSelectedRowKeys();
|
createMessage.success(res.msg);
|
});
|
}
|
function handleTreeSearch(value) {
|
state.keyword = value;
|
initGroupList(false);
|
}
|
|
onMounted(() => {
|
initGroupList();
|
initOptions();
|
});
|
</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 !w-[260px]">
|
<BasicLeftTree title="用户" ref="leftTreeRef" v-bind="getTreeBindValue">
|
<template #headerToolbar>
|
<i class="icon-ym icon-ym-btn-add cursor-pointer" @click="addOrUpdateGroupHandle()"></i>
|
</template>
|
</BasicLeftTree>
|
</div>
|
<div class="jnpf-content-wrapper-center">
|
<div class="jnpf-content-wrapper-content">
|
<BasicVxeTable @register="registerTable" :search-info="searchInfo">
|
<template #tableTitle>
|
<div v-show="false">
|
<jnpf-pos-select ref="postSelectRef" v-model:value="state.currentPosId" multiple @change="onAdjustPositionChange" />
|
<jnpf-pos-select ref="batchPostSelectRef" multiple @change="onBatchAdjustPositionChange" />
|
</div>
|
<template v-if="!searchInfo.groupId">
|
<template v-if="!getSelectRowLen">
|
<a-button type="primary" pre-icon="icon-ym icon-ym-btn-add" @click="addOrUpdateHandle()">{{ $t('common.addText') }}</a-button>
|
<a-dropdown>
|
<template #overlay>
|
<a-menu @click="handleSync">
|
<a-menu-item :key="0"><i class="icon-ym icon-ym-logo-dingding pr-[5px]"></i>钉钉同步</a-menu-item>
|
<a-menu-item :key="1"><i class="icon-ym icon-ym-logo-wxWork pr-[5px]"></i>企微同步</a-menu-item>
|
</a-menu>
|
</template>
|
<a-button type="primary" pre-icon="icon-ym icon-ym-synForThird">{{ $t('common.syncUser') }}<DownOutlined /></a-button>
|
</a-dropdown>
|
<a-button type="link" @click="handleExport"><i class="icon-ym icon-ym-btn-download"></i>{{ $t('common.exportText') }}</a-button>
|
<a-button type="link" @click="handleImport"><i class="icon-ym icon-ym-btn-upload"></i>{{ $t('common.importText') }}</a-button>
|
</template>
|
<template v-else>
|
<a-button type="link" class="!pt-[6px]" @click="handleBatchAdjustPosition">
|
<i class="icon-ym icon-ym-app-move text-[14px]"></i>调整岗位
|
</a-button>
|
<a-button type="link" @click="handleBatchUpdateState(1)" class="!pt-[6px]">
|
<i class="icon-ym icon-ym-flow-node-start text-[14px]"></i>启用
|
</a-button>
|
<a-button type="link" @click="handleBatchUpdateState(0)"><i class="ym-custom ym-custom-stop-circle-outline"></i>禁用</a-button>
|
<a-button type="link" @click="handleBatchUpdateState(2)"><i class="ym-custom ym-custom-lock-open-outline"></i>锁定</a-button>
|
<a-button type="link" @click="handleBatchDel"><i class="icon-ym icon-ym-delete"></i>{{ $t('common.delText') }}</a-button>
|
</template>
|
</template>
|
<template v-else>
|
<a-dropdown>
|
<template #overlay>
|
<a-menu @click="handleAdd">
|
<a-menu-item :key="0"><i class="icon-ym icon-ym-btn-add pr-[5px]"></i>新建用户</a-menu-item>
|
<a-menu-item :key="2">
|
<jnpf-user-select multiple required @change="handleAddGroupUser">
|
<template #action> <i class="icon-ym icon-ym icon-ym-generator-user pr-[5px]"></i>选择用户 </template>
|
</jnpf-user-select>
|
</a-menu-item>
|
</a-menu>
|
</template>
|
<a-button type="primary" pre-icon="icon-ym icon-ym-btn-add">添加用户<DownOutlined /></a-button>
|
</a-dropdown>
|
<a-button type="link" @click="handleBatchRemove()"><i class="icon-ym icon-ym-add-cancel"></i>移除</a-button>
|
</template>
|
</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>
|
<template #action="{ record }">
|
<TableAction :actions="getTableActions(record)" :drop-down-actions="getDropDownActions(record)" v-if="!record.isAdministrator" />
|
</template>
|
</BasicVxeTable>
|
</div>
|
</div>
|
</div>
|
<Form @register="registerForm" @reload="reload" />
|
<ResetPassword @register="registerPsdModal" />
|
<SocialsBind @register="registerSocialsBind" />
|
<ExportModal @register="registerExportModal" />
|
<ImportModal @register="registerImportModal" @reload="reload" />
|
<WorkHandoverModal @register="registerWorkHandoverModal" @reload="reload" />
|
<PermissionPopup @register="registerPermission" />
|
<GroupForm @register="registerGroupForm" @reload="initGroupList(false)" />
|
</div>
|
</template>
|