feat: 同步用户接口

This commit is contained in:
JiangQiming 2023-01-30 17:06:50 +08:00
parent 9f0e384be6
commit 05e1281728
4 changed files with 386 additions and 10 deletions

View File

@ -16,9 +16,9 @@ export default {
debug: (data: any, configId: string, templateId: string) => post(`/notifier/${configId}/${templateId}/_send`, data), debug: (data: any, configId: string, templateId: string) => post(`/notifier/${configId}/${templateId}/_send`, data),
getHistory: (data: any, id: string) => post(`/notify/history/config/${id}/_query`, data), getHistory: (data: any, id: string) => post(`/notify/history/config/${id}/_query`, data),
// 获取所有平台用户 // 获取所有平台用户
getPlatformUsers: () => post(`/user/_query/no-paging`, { paging: false }), getPlatformUsers: () => post<any>(`/user/_query/no-paging`, { paging: false }),
// 钉钉部门 // 钉钉部门
dingTalkDept: (id: string) => get(`/notifier/dingtalk/corp/${id}/departments/tree`), dingTalkDept: (id: string) => get<any>(`/notifier/dingtalk/corp/${id}/departments/tree`),
// 钉钉部门人员 // 钉钉部门人员
getDingTalkUsers: (configId: string, deptId: string) => get(`/notifier/dingtalk/corp/${configId}/${deptId}/users`), getDingTalkUsers: (configId: string, deptId: string) => get(`/notifier/dingtalk/corp/${configId}/${deptId}/users`),
// 钉钉已经绑定的人员 // 钉钉已经绑定的人员
@ -26,7 +26,7 @@ export default {
// 钉钉绑定用户 // 钉钉绑定用户
dingTalkBindUser: (data: any, id: string) => patch(`/user/third-party/dingTalk_dingTalkMessage/${id}`, data), dingTalkBindUser: (data: any, id: string) => patch(`/user/third-party/dingTalk_dingTalkMessage/${id}`, data),
// 微信部门 // 微信部门
weChatDept: (id: string) => get(`/notifier/wechat/corp/${id}/departments`), weChatDept: (id: string) => get<any>(`/notifier/wechat/corp/${id}/departments`),
// 微信部门人员 // 微信部门人员
getWeChatUsers: (configId: string, deptId: string) => get(`/notifier/wechat/corp/${configId}/${deptId}/users`), getWeChatUsers: (configId: string, deptId: string) => get(`/notifier/wechat/corp/${configId}/${deptId}/users`),
// 微信已经绑定的人员 // 微信已经绑定的人员

View File

@ -39,6 +39,7 @@ const iconKeys = [
'ArrowDownOutlined', 'ArrowDownOutlined',
'SmallDashOutlined', 'SmallDashOutlined',
'TeamOutlined', 'TeamOutlined',
'SearchOutlined',
] ]
const Icon = (props: {type: string}) => { const Icon = (props: {type: string}) => {

View File

@ -1,13 +1,374 @@
<template> <template>
<div class="page-container"> <a-modal
v-model:visible="_vis"
</div> title="同步用户"
:footer="null"
@cancel="_vis = false"
width="80%"
>
<a-row :gutter="10">
<a-col :span="4">
<a-input
v-model:value="deptName"
@keyup.enter="getDepartment"
allowClear
placeholder="请输入部门名称"
style="margin-bottom: 8px"
>
<template #addonAfter>
<AIcon
type="SearchOutlined"
style="cursor: pointer"
@click="getDepartment"
/>
</template>
</a-input>
<a-tree
:tree-data="deptTreeData"
:fieldNames="{ title: 'name', key: 'id' }"
:selectedKeys="[deptId]"
@select="onTreeSelect"
>
</a-tree>
<a-empty v-if="!deptTreeData.length" />
</a-col>
<a-col :span="20">
<JTable
ref="tableRef"
:columns="columns"
:dataSource="dataSource"
:loading="tableLoading"
model="table"
>
<template #headerTitle>
<a-button type="primary" @click="handleAutoBind">
自动绑定
</a-button>
</template>
<template #status="slotProps">
<a-space>
<a-badge
:status="slotProps.status.value"
:text="slotProps.status.text"
></a-badge>
<AIcon
v-if="slotProps.status.value === 'error'"
type="ExclamationCircleOutlined"
style="color: #1d39c4; cursor: pointer"
@click="handleError(slotProps.errorStack)"
/>
</a-space>
</template>
<template #action="slotProps">
<a-space :size="16">
<a-tooltip
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
v-bind="i.tooltip"
>
<a-popconfirm
v-if="i.popConfirm"
v-bind="i.popConfirm"
:disabled="i.disabled"
>
<a-button
:disabled="i.disabled"
style="padding: 0"
type="link"
><AIcon :type="i.icon"
/></a-button>
</a-popconfirm>
<a-button
style="padding: 0"
type="link"
v-else
@click="i.onClick && i.onClick(slotProps)"
>
<a-button
:disabled="i.disabled"
style="padding: 0"
type="link"
><AIcon :type="i.icon"
/></a-button>
</a-button>
</a-tooltip>
</a-space>
</template>
</JTable>
</a-col>
</a-row>
</a-modal>
</template> </template>
<script setup lang="ts"> <script setup lang="ts" name="SyncUser">
import configApi from '@/api/notice/config';
import { PropType } from 'vue';
import moment from 'moment';
import { Modal, message } from 'ant-design-vue';
import type { ActionsType } from '@/components/Table/index.vue';
type Emits = {
(e: 'update:visible', data: boolean): void;
};
const emit = defineEmits<Emits>();
const props = defineProps({
visible: { type: Boolean, default: false },
data: {
type: Object as PropType<Partial<Record<string, any>>>,
default: () => ({}),
},
});
const _vis = computed({
get: () => props.visible,
set: (val) => emit('update:visible', val),
});
watch(
() => _vis.value,
(val) => {
if (val) {
getDepartment();
}
},
);
//
const deptTreeData = ref([]);
const deptName = ref('');
const deptId = ref('');
/**
* 获取部门
*/
const getDepartment = async () => {
let res = null;
if (props.data.type === 'dingTalk') {
res = await configApi.dingTalkDept(props.data.id);
} else if (props.data.type === 'weixin') {
res = await configApi.weChatDept(props.data.id);
}
let _result = res?.result;
if (deptName.value) {
_result = res?.result?.filter(
(f: any) => f.name.indexOf(deptName.value) > -1,
);
}
// deptTreeData.value = arrayToTree(_result, _result[0]?.parentId);
deptTreeData.value = _result;
deptId.value = _result[0]?.id;
};
/**
* 扁平数据转树形结构
*/
// const arrayToTree = (arr: any, pid: string | number) => {
// return arr
// .filter((item: any) => item.parentId === pid)
// .map((item: any) => ({
// ...item,
// children: arrayToTree(arr, item.id),
// }));
// };
/**
* 部门点击
*/
const onTreeSelect = (keys: any) => {
deptId.value = keys[0];
};
//
const columns = [
{
title: '钉钉用户名',
dataIndex: 'thirdPartyUserName',
key: 'thirdPartyUserName',
},
{
title: '用户',
dataIndex: 'userName',
key: 'userName',
scopedSlots: true,
},
{
title: '绑定状态',
dataIndex: 'status',
key: 'status',
scopedSlots: true,
},
{
title: '操作',
key: 'action',
scopedSlots: true,
},
];
const getActions = (
data: Partial<Record<string, any>>,
type: 'card' | 'table',
): ActionsType[] => {
if (!data) return [];
const actions = [
{
key: 'bind',
text: '绑定',
tooltip: {
title: '绑定',
},
icon: 'EditOutlined',
onClick: () => {
// visible.value = true;
// current.value = data;
},
},
{
key: 'unbind',
text: '解绑',
icon: 'DisconnectOutlined',
popConfirm: {
title: '确认解绑?',
onConfirm: async () => {
configApi
.unBindUser({ bindingId: data.bindId }, data.bindId)
.then(() => {
message.success('操作成功');
getTableData();
});
},
},
},
];
if (data.status.value === 'success') return actions;
return actions.filter((i: ActionsType) => i.key !== 'unbind');
};
/**
* 自动绑定
*/
const handleAutoBind = () => {
configApi.dingTalkBindUser([], props.data.id).then(() => {
message.success('操作成功');
getTableData();
});
};
/**
* 获取钉钉部门用户
*/
const getDeptUsers = async () => {
let res = null;
if (props.data.type === 'dingTalk') {
res = await configApi.getDingTalkUsers(props.data.id, deptId.value);
} else if (props.data.type === 'weixin') {
res = await configApi.getWeChatUsers(props.data.id, deptId.value);
}
return res?.result;
};
/**
* 获取已经绑定的用户
*/
const getBindUsers = async () => {
let res = null;
if (props.data.type === 'dingTalk') {
res = await configApi.getDingTalkBindUsers(props.data.id);
} else if (props.data.type === 'weixin') {
res = await configApi.getWeChatBindUsers(props.data.id);
}
return res?.result;
};
/**
* 获取所有用户
*/
const allUserList = ref([]);
const getAllUsers = async () => {
const { result } = await configApi.getPlatformUsers();
allUserList.value = result.map((m: any) => ({
label: m.name,
value: m.id,
}));
return result;
};
/**
* 处理列表数据
*/
const dataSource = ref<any>([]);
const tableLoading = ref(false);
const getTableData = () => {
tableLoading.value = true;
Promise.all<any>([getDeptUsers(), getBindUsers(), getAllUsers()]).then(
(res) => {
dataSource.value = [];
const [deptUsers, bindUsers, allUsers] = res;
(deptUsers || []).forEach((item: any) => {
//
const bindUser = bindUsers.find(
(f: any) => f.thirdPartyUserId === item.id,
);
//
const allUser = allUsers.find(
(f: any) => f.id === bindUser?.userId,
);
dataSource.value.push({
thirdPartyUserId: item.id,
thirdPartyUserName: item.name,
userId: bindUser?.userId,
userName: allUser
? `${allUser.name}(${allUser.username})`
: '',
status: {
text: bindUser?.providerName ? '已绑定' : '未绑定',
value: bindUser?.providerName ? 'success' : 'error',
},
bindId: bindUser?.id,
});
});
console.log('dataSource.value: ', dataSource.value);
},
);
tableLoading.value = false;
};
watch(
() => deptId.value,
() => {
getTableData();
},
{ immediate: true },
);
/**
* 绑定用户
*/
const bindVis = ref(false);
const formData = ref({});
const handleBind = (row: any) => {
bindVis.value = true;
formData.value = row;
getAllUsers();
};
/**
* 查看错误信息
*/
const handleError = (e: any) => {
Modal.info({
title: '错误信息',
content: JSON.stringify(e),
});
};
/**
* 查看详情
*/
const handleDetail = (e: any) => {
Modal.info({
title: '详情信息',
content: JSON.stringify(e),
});
};
</script> </script>
<style lang="less" scoped> <style lang="less" scoped></style>
</style>

View File

@ -362,6 +362,18 @@ const getActions = (
downloadObject(data, `通知配置`); downloadObject(data, `通知配置`);
}, },
}, },
{
key: 'sync',
text: '同步用户',
tooltip: {
title: '同步用户',
},
icon: 'TeamOutlined',
onClick: () => {
syncVis.value = true;
currentConfig.value = data;
},
},
{ {
key: 'delete', key: 'delete',
text: '删除', text: '删除',
@ -380,7 +392,9 @@ const getActions = (
icon: 'DeleteOutlined', icon: 'DeleteOutlined',
}, },
]; ];
return actions; if (data.provider === 'dingTalkMessage' || data.provider === 'corpMessage')
return actions;
return actions.filter((i: ActionsType) => i.key !== 'sync');
}; };
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>