<!-- Props:
|
|
modelValue: 控制抽屉的打开与关闭。
|
title: 抽屉标题,默认为Basic Drawer。
|
placement: 抽屉位置,默认为right。
|
Emits:
|
|
update:modelValue: 当内部状态改变时,更新外部绑定的modelValue。
|
计算属性:
|
|
title 和 placement 用于获取属性值或默认值。
|
内部状态:
|
|
drawerOpen 用于控制抽屉的状态。
|
方法:
|
|
showDrawer 用于显示抽屉。 -->
|
|
<template>
|
<a-drawer
|
v-model:open="drawerOpen"
|
:title="title"
|
:placement="placement"
|
:width="1200"
|
:body-style="{ paddingBottom: '80px' }"
|
:footer-style="{ textAlign: 'right' }"
|
@after-open-change="afterOpenChange"
|
@close="afterOpenChange"
|
>
|
<a-tabs v-model:activeKey="activeKey">
|
<a-tab-pane :key="item.key" :tab="item.title" v-for="item in tabsList">
|
<a-form :model="form" :rules="rules" layout="vertical">
|
<a-row :gutter="16">
|
<a-col :span="12">
|
<a-form-item label="关键字">
|
<a-input v-model:value="form.keyword" placeholder="编号/联系人名称" />
|
</a-form-item>
|
</a-col>
|
</a-row>
|
</a-form>
|
<div class="table-content">
|
<div class="left">
|
<a-card
|
:bordered="false"
|
:title="`联系人(${selectContactNum})`"
|
style="height: 500px"
|
>
|
<template #extra>
|
<a-checkbox v-model:checked="selectAllCurrentPage" @change="fnSelectAllCurrentPage"
|
>全选当前页</a-checkbox
|
>
|
<a-checkbox v-model:checked="selectEmail" @change="fnSelectEmail"
|
>选择前30个邮箱</a-checkbox
|
></template
|
>
|
<a-table
|
:showHeader="false"
|
:data-source="dataSource"
|
:row-selection="{
|
selectedRowKeys: state.selectedRowKeys,
|
onChange: onSelectChange,
|
}"
|
:scroll="{ y: 300 }"
|
size="small"
|
rowKey="email"
|
>
|
<!-- :pagination="{ pageSize: 100 }" -->
|
<a-table-column key="userName" title="name" data-index="name">
|
<template #default="{ record }">
|
<span>{{ record.userName }}</span
|
><span>{{ `<${record.email}>` }}</span>
|
<span style="margin-left: 5px">{{ record.ccName }}</span>
|
</template>
|
</a-table-column>
|
</a-table>
|
</a-card>
|
</div>
|
<div class="right">
|
<a-card
|
:bordered="false"
|
:title="`已选联系人(${contactNum}/100)`"
|
style="height: 500px"
|
>
|
<template #extra><a @click="fnClearSelect">清空选项</a></template>
|
<a-table
|
:showHeader="false"
|
:data-source="tempDataSource"
|
:pagination="false"
|
:scroll="{ y: 355 }"
|
size="small"
|
>
|
<a-table-column key="userName" title="name" data-index="name">
|
<template #default="{ record }">
|
<span>{{ record.userName }}</span
|
><span>{{ `<${record.email}>` }}</span>
|
<!-- <span style="margin-left: 5px">{{ record.ccName }}</span> -->
|
</template>
|
</a-table-column>
|
</a-table>
|
</a-card>
|
</div>
|
</div>
|
</a-tab-pane>
|
</a-tabs>
|
|
<template #extra>
|
<a-space>
|
<a-button @click="afterOpenChange">取消</a-button>
|
<a-button type="primary" @click="fnSaveOpenChange">保存</a-button>
|
</a-space>
|
</template>
|
</a-drawer>
|
</template>
|
|
<script lang="ts" setup>
|
import { ref, watch, defineProps, defineEmits, computed, reactive } from 'vue';
|
import { getUserInfoApi } from '@/api/email/userList';
|
// 定义组件名称
|
defineOptions({ name: 'SelectUser' });
|
|
// 定义属性
|
interface Props {
|
modelValue: boolean;
|
title?: string;
|
placement?: 'left' | 'right' | 'top' | 'bottom';
|
idName?: string;
|
selectIds?: number[];
|
}
|
const props = defineProps<Props>();
|
|
const activeKey = ref('3');
|
const tabsList = ref([
|
{
|
key: '1',
|
title: '客户联系人',
|
},
|
{
|
key: '2',
|
title: '线索联系人',
|
},
|
{
|
key: '3',
|
title: '商机联系人',
|
},
|
{
|
key: '4',
|
title: '企业同事',
|
},
|
{
|
key: '5',
|
title: '个人通讯录',
|
},
|
{
|
key: '6',
|
title: '企业通讯录',
|
},
|
]);
|
|
// 定义事件
|
const emit = defineEmits(['update:modelValue', 'updateData','sudUserList']);
|
|
// 内部状态
|
const drawerOpen = ref(props.modelValue);
|
|
// 监听属性变化
|
watch(
|
() => props.modelValue,
|
(newValue) => {
|
drawerOpen.value = newValue;
|
if (props.selectIds && props.selectIds.length > 0) {
|
state.selectedRowKeys = props.selectIds;
|
updateTempDataSource(props.selectIds);
|
} else {
|
state.selectedRowKeys = [];
|
updateTempDataSource([]);
|
}
|
},
|
);
|
|
// 更新外部属性
|
watch(drawerOpen, (newValue) => {
|
emit('update:modelValue', newValue);
|
});
|
// 方法
|
const afterOpenChange = (bool: boolean) => {
|
if (bool) {
|
fnGetUserList({});
|
}
|
};
|
interface User {
|
ccCode: string;
|
ccName: string;
|
userCode: string;
|
userName: string;
|
email: string;
|
}
|
const fnGetUserList = (params) =>
|
getUserInfoApi(params).then((res) => {
|
if (res && res.data && Array.isArray(res.data)) {
|
dataSource.value = flattenAndDeduplicateData(res.data) || ([] as User[]);
|
selectContactNum.value = dataSource.value.length;
|
emit('sudUserList', dataSource.value)
|
} else {
|
console.error('Invalid response format:', res);
|
}
|
});
|
|
function flattenAndDeduplicateData(data) {
|
const result: Record<string, any>[] = [];
|
const userCodeSet = new Set(); // 用于记录已经出现过的 userCode
|
|
data.forEach((department) => {
|
const { ccCode, ccName, subList } = department;
|
|
if (subList && subList.length > 0) {
|
subList.forEach((user) => {
|
// 如果 userCode 不在 Set 中,才添加到结果中
|
if (!userCodeSet.has(user.userCode)) {
|
result.push({
|
ccCode: user.ccCode || ccCode, // 使用子项或父项的 ccCode
|
ccName: user.ccName || ccName, // 使用子项或父项的 ccName
|
userCode: user.userCode,
|
userName: user.userName,
|
id: user.userCode,
|
email: user.email || '', // 确保 email 不为 null
|
});
|
// 将 userCode 加入 Set,避免重复
|
userCodeSet.add(user.userCode);
|
}
|
});
|
}
|
});
|
|
return result;
|
}
|
// 计算属性
|
const title = computed(() => props.title || 'Basic Drawer');
|
const placement = computed(() => props.placement || 'right');
|
const idName = computed(() => props.idName || 'recipients');
|
|
// // 显示抽屉的方法
|
// const showDrawer = () => {
|
// drawerOpen.value = true;
|
// };
|
|
const form = ref({
|
keyword: '',
|
});
|
const rules = ref({
|
keyword: [{ required: true, message: '关键字不能为空', trigger: 'blur' }],
|
});
|
const selectAllCurrentPage = ref(false);
|
const selectEmail = ref(false);
|
const fnSelectAllCurrentPage = (e) => {
|
const temp = dataSource.value;
|
if (selectAllCurrentPage.value) {
|
state.selectedRowKeys = temp.map((item) => item.id);
|
} else {
|
state.selectedRowKeys = state.selectedRowKeys.filter(
|
(item) => !temp.some((t) => t.id === item),
|
);
|
}
|
updateTempDataSource(state.selectedRowKeys);
|
};
|
|
const fnSelectEmail = (e) => {
|
const temp = dataSource.value.slice(0, 30);
|
if (selectEmail.value) {
|
state.selectedRowKeys = temp.map((item) => item.id);
|
} else {
|
state.selectedRowKeys = state.selectedRowKeys.filter(
|
(item) => !temp.some((t) => t.id === item),
|
);
|
}
|
updateTempDataSource(state.selectedRowKeys);
|
};
|
const updateTempDataSource = (selectedRowKeys: Key[]) => {
|
tempDataSource.value = dataSource.value.filter((item) => selectedRowKeys.includes(item.id));
|
contactNum.value = selectedRowKeys.length;
|
};
|
|
const contactNum = ref(0);
|
const selectContactNum = ref(0);
|
|
const dataSource = ref<Record<string, any>>([]);
|
|
type Key = string | number;
|
const state = reactive<{
|
selectedRowKeys: Key[];
|
loading: boolean;
|
}>({
|
selectedRowKeys: [], // Check here to configure the default column
|
loading: false,
|
});
|
const tempDataSource = ref([]);
|
|
const fnClearSelect = () => {
|
state.selectedRowKeys = [];
|
tempDataSource.value = [];
|
contactNum.value = 0;
|
};
|
const onSelectChange = (selectedRowKeys: Key[]) => {
|
state.selectedRowKeys = selectedRowKeys;
|
|
tempDataSource.value = dataSource.value.filter((item) => selectedRowKeys.includes(item.id));
|
contactNum.value = selectedRowKeys.length;
|
|
};
|
const fnSaveOpenChange = () => {
|
console.log('selectedRowKeys changed: ', state.selectedRowKeys);
|
drawerOpen.value = false;
|
emit('update:modelValue', false);
|
const data = {
|
selectedRowKeys: state.selectedRowKeys,
|
idName: idName.value,
|
};
|
emit('updateData', data);
|
};
|
</script>
|
|
<style scoped lang="less">
|
/* 样式可以在这里定义 */
|
|
.table-content {
|
display: flex;
|
justify-content: space-between;
|
border-top: 1px solid #f0f0f0;
|
|
.left {
|
width: 50%;
|
height: 100%;
|
border-right: 1px solid #f0f0f0;
|
}
|
|
.right {
|
width: 50%;
|
height: 100%;
|
}
|
}
|
|
::v-deep(.ant-table) {
|
min-height: 355px !important;
|
}
|
</style>
|