<template>
|
<div class="p-3">
|
<a-spin :spinning="loading" class="p-1">
|
<a-form ref="formRef" :label-col="{ span: 2 }" :wrapper-col="{ span: 24 }" :model="modelRef">
|
<a-form-item :wrapper-col="{ span: 8 }">
|
<div style="display: flex; justify-content: space-evenly">
|
<a-button type="primary" shape="round" @click="fnHandleSubmit(modelRef)">发送</a-button>
|
<a-button shape="round" @click="fnSaveMailDrafts">存草稿</a-button>
|
<a-button shape="round" @click="fnPreview">预览</a-button>
|
<a-button shape="round">提交审批</a-button>
|
<a-button shape="round">取消</a-button></div
|
>
|
</a-form-item>
|
<a-form-item label="发件人" v-bind="validateInfos.sender" :wrapper-col="{ span: 12 }">
|
<a-select
|
v-model:value="modelRef.sender"
|
placeholder="选择发件人"
|
show-search
|
:field-names="{ label: 'email', value: 'email' }"
|
:options="state.senderList"
|
:filter-option="fnFilterOption"
|
>
|
</a-select>
|
</a-form-item>
|
<a-form-item label="收件人" v-bind="validateInfos.recipients" :wrapper-col="{ span: 18 }">
|
<a-row>
|
<a-col class="gutter-row" :span="16">
|
<a-select
|
mode="tags"
|
placeholder="请选择收件人或者输入收件人邮箱"
|
v-model:value="modelRef.recipients"
|
:options="state.recipientsList"
|
:field-names="{ label: 'email', value: 'email' }"
|
:maxTagCount="4"
|
@search="fetchUser"
|
>
|
<template #tagRender="{ label, closable, onClose, option }">
|
<a-tag
|
:closable="closable"
|
style="margin-right: 3px"
|
@close="onClose"
|
:color="validateEmail(label) ? 'default' : 'red'"
|
>
|
{{ label }}
|
</a-tag>
|
</template>
|
</a-select>
|
</a-col>
|
<a-col
|
class="gutter-row"
|
:span="2"
|
style="display: flex; align-items: center; justify-content: center"
|
>
|
<plus-circle-outlined
|
style="color: rgb(0 0 0 / 45%)"
|
@click="fnHandleSelect('recipients')"
|
/>
|
</a-col>
|
<a-col class="gutter-row" :span="1">
|
<a-form-item-rest>
|
<a-button
|
shape="round"
|
type="link"
|
block
|
size="small"
|
@click="ccCheckboxChange($event)"
|
>
|
{{ !isSecretDeliveryPerson ? '抄送' : '取消抄送' }}
|
</a-button>
|
</a-form-item-rest>
|
</a-col>
|
<a-col class="gutter-row" :span="1">
|
<a-form-item-rest>
|
<a-button
|
shape="round"
|
type="link"
|
block
|
size="small"
|
@click="bccCheckboxChange($event)"
|
>
|
{{ !isCRecipient ? '密送' : '取消密送' }}
|
</a-button>
|
</a-form-item-rest>
|
</a-col>
|
</a-row>
|
</a-form-item>
|
<span style="position: relative; top: -18px; left: 9%" v-if="modelRef.recipients.length">
|
{{ userParticulars && `${userParticulars.userName}<${userParticulars.email}` }}>
|
<span v-if="!userParticulars.title" style="margin-right: 10px; margin-left: 5px">
|
暂未查询到该客户的当地时间
|
<a @click="fnHandleTimeZone(userParticulars, 'add')">补充时区</a>
|
</span>
|
<span v-else>
|
{{ userParticulars.title }}
|
<a @click="fnHandleTimeZone(userParticulars, 'update')">时区不对?</a>
|
</span>
|
|
<a v-if="modelRef.recipients.length > 2">查看全部</a>
|
</span>
|
|
<a-form-item
|
label="抄送人"
|
v-bind="validateInfos.ccRecipients"
|
v-if="isSecretDeliveryPerson"
|
:wrapper-col="{ span: 18 }"
|
>
|
<a-row>
|
<a-col class="gutter-row" :span="16">
|
<a-select
|
mode="tags"
|
placeholder="请选择抄送人或者输入抄送人邮箱"
|
v-model:value="modelRef.ccRecipients"
|
:options="state.recipientsList"
|
:field-names="{ label: 'email', value: 'email' }"
|
:maxTagCount="4"
|
>
|
<template #tagRender="{ label, closable, onClose }">
|
<a-tag
|
:closable="closable"
|
style="margin-right: 3px"
|
@close="onClose"
|
:color="validateEmail(label) ? 'default' : 'red'"
|
>
|
{{ label }}
|
</a-tag>
|
</template>
|
</a-select>
|
</a-col>
|
<a-col
|
class="gutter-row"
|
:span="2"
|
style="display: flex; align-items: center; justify-content: center"
|
>
|
<plus-circle-outlined
|
style="color: rgb(0 0 0 / 45%)"
|
@click="fnHandleSelect('ccRecipients')"
|
/>
|
</a-col>
|
</a-row>
|
</a-form-item>
|
<a-form-item
|
label="密送人"
|
v-bind="validateInfos.bccRecipients"
|
v-if="isCRecipient"
|
:wrapper-col="{ span: 18 }"
|
>
|
<a-row>
|
<a-col class="gutter-row" :span="16">
|
<a-select
|
mode="tags"
|
placeholder="请选择抄送人或者输入抄送人邮箱"
|
v-model:value="modelRef.bccRecipients"
|
:options="state.recipientsList"
|
:field-names="{ label: 'email', value: 'email' }"
|
:maxTagCount="4"
|
>
|
<template #tagRender="{ label, closable, onClose }">
|
<a-tag
|
:closable="closable"
|
style="margin-right: 3px"
|
@close="onClose"
|
:color="validateEmail(label) ? 'default' : 'red'"
|
>
|
{{ label }}
|
</a-tag>
|
</template>
|
</a-select>
|
</a-col>
|
<a-col
|
class="gutter-row"
|
:span="2"
|
style="display: flex; align-items: center; justify-content: center"
|
>
|
<plus-circle-outlined
|
style="color: rgb(0 0 0 / 45%)"
|
@click="fnHandleSelect('bccRecipients')"
|
/>
|
</a-col>
|
</a-row>
|
</a-form-item>
|
<div
|
style="position: relative; top: -20px; left: 9%; color: #909090; font-size: 12px"
|
v-if="modelRef.recipients.length"
|
>
|
{{ `${userLength}/100 收件人、抄送人和密送的联系人总数不可超过100` }}
|
</div>
|
<a-form-item label="主题" :wrapper-col="{ span: 12 }" :label-col="{ span: 2 }">
|
<a-input placeholder="请输入邮件主题" v-model:value="modelRef.subject" />
|
</a-form-item>
|
<a-form-item
|
v-bind="validateInfos.content"
|
:wrapper-col="{ span: 24 }"
|
:label-col="{ span: 2 }"
|
>
|
<Tinymce v-model="modelRef.content" @change="fnChangeContent"></Tinymce>
|
</a-form-item>
|
</a-form>
|
</a-spin>
|
<SelectUser
|
ref="selectUserRef"
|
v-model="openSelectUser"
|
:selectIds="selectIds"
|
:idName="idName"
|
:title="selectUserTitle"
|
@updateData="fnSelectUser"
|
/>
|
<a-modal
|
v-model:open="openTimeZone"
|
:title="`${titleTimeZone}时区`"
|
:confirm-loading="confirmLoading"
|
@ok="fnHandleTimeZoneOk"
|
>
|
<a-form
|
ref="formTimeZoneRef"
|
:label-col="{ span: 6 }"
|
:wrapper-col="{ span: 24 }"
|
:model="modelRef"
|
>
|
<a-form-item label="国家地区:" :wrapper-col="{ span: 12 }">
|
<a-select
|
v-model:value="modelRef.sender"
|
placeholder="选择国家地区"
|
show-search
|
:field-names="{ label: 'name', value: 'id' }"
|
:options="state.data"
|
>
|
</a-select>
|
</a-form-item>
|
<a-form-item label="时区:" :wrapper-col="{ span: 12 }">
|
<a-select
|
v-model:value="modelRef.sender"
|
placeholder="选择时区"
|
show-search
|
:field-names="{ label: 'name', value: 'id' }"
|
:options="state.data"
|
>
|
</a-select>
|
</a-form-item>
|
<a-form-item :label-col="{ span: 6 }">
|
<a-row>
|
<a-col span="6"> </a-col>
|
<a-col span="18">
|
<div style="color: #909090"
|
>当地实时时间根据时区信息显示<br />
|
国家地区/时区信息在客户资料-特征信息查看</div
|
>
|
</a-col>
|
</a-row>
|
</a-form-item>
|
</a-form>
|
</a-modal>
|
</div>
|
</template>
|
|
<script lang="ts" setup>
|
name: 'Edit';
|
import { useDesign } from '@/hooks/web/useDesign';
|
|
import { ref, reactive, computed, onMounted } from 'vue';
|
import { useMessage } from '@/hooks/web/useMessage';
|
import { Tinymce } from '@/components/Tinymce';
|
import { PlusCircleOutlined } from '@ant-design/icons-vue';
|
import SelectUser from '../components/SelectUser/index.vue';
|
import { Form } from 'ant-design-vue';
|
const modelRef = reactive({
|
sender: '',
|
recipients: [],
|
ccRecipients: [],
|
bccRecipients: [],
|
attachmentList: [],
|
subject: '',
|
content: '',
|
});
|
const loading = ref(false);
|
const rulesRef = reactive({
|
sender: [
|
{
|
required: true,
|
message: '发件人不能为空',
|
},
|
],
|
recipients: [
|
{
|
required: true,
|
message: '收件人不能为空',
|
},
|
],
|
content: [
|
{
|
required: true,
|
message: '内容不能为空',
|
},
|
],
|
});
|
const TYPE = computed(() => {
|
return router.currentRoute.value.query.type || 'send';
|
});
|
onMounted(() => {
|
fnGetRecipientsList();
|
if (TYPE.value === 'reply') {
|
fuGetReplyEmailData();
|
}
|
});
|
const useForm = Form.useForm;
|
const { validate, validateInfos } = useForm(modelRef, rulesRef);
|
|
const formRef = ref();
|
|
let isSecretDeliveryPerson = ref(false);
|
|
let isCRecipient = ref(false);
|
const handleCheckboxChange = (ref, e) => {
|
ref.value = !ref.value;
|
};
|
|
const ccCheckboxChange = (e) => {
|
handleCheckboxChange(isSecretDeliveryPerson, e);
|
};
|
const bccCheckboxChange = (e) => {
|
handleCheckboxChange(isCRecipient, e);
|
};
|
|
const { createMessage } = useMessage();
|
import {
|
getAccountListApi,
|
sendingMailApi,
|
saveMailDraftsApi,
|
emailListAPi,
|
getMailInfoApi
|
} from '@/api/email/userList';
|
// 定义状态管理对象
|
const state = reactive({
|
data: [],
|
fetching: false,
|
error: null,
|
senderList: [],
|
recipientsList: [],
|
});
|
|
// 获取用户列表的函数
|
const fnGetUserList = async (params) => {
|
try {
|
state.fetching = true;
|
const res = await getAccountListApi();
|
console.log(res, 'res');
|
|
if (res && res.data && Array.isArray(res.data)) {
|
state.senderList = res.data;
|
} else {
|
console.error('Invalid response format:', res);
|
}
|
} catch (error) {
|
console.error('Failed to fetch user list:', error);
|
} finally {
|
state.fetching = false;
|
}
|
};
|
|
// 初始化用户数据
|
const fetchData = async () => {
|
await fnGetUserList({ page: 1, pageSize: 30 });
|
};
|
console.log(state.data, 'state.data');
|
// 调用初始化函数
|
fetchData();
|
|
const fnFilterOption = (input: string, option: any) => {
|
return option.email.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
};
|
|
const openSelectUser = ref(false);
|
const selectUserTitle = ref('选择收件人');
|
const selectIds = ref([]);
|
const idName = ref('');
|
const fnHandleSelect = (e) => {
|
if (e === 'recipients') {
|
selectUserTitle.value = '选择收件人';
|
idName.value = e;
|
}
|
if (e === 'ccRecipients') {
|
selectUserTitle.value = '选择抄送人';
|
idName.value = e;
|
}
|
if (e === 'bccRecipients') {
|
selectUserTitle.value = '选择密送人';
|
idName.value = e;
|
}
|
selectIds.value = modelRef[e];
|
openSelectUser.value = true;
|
};
|
|
function fnChangeContent(e) {
|
modelRef.content = e.content;
|
modelRef.attachmentList = e.attachmentList;
|
}
|
|
function fnBuildingCommitData() {
|
return {
|
sender: modelRef.sender,
|
receiver: modelRef.recipients,
|
cc: modelRef.ccRecipients,
|
bcc: modelRef.bccRecipients,
|
subject: modelRef.subject,
|
content: modelRef.content,
|
attachmentList: '',
|
docCode: docCode.value,
|
};
|
}
|
const docCode = ref('');
|
import { Modal } from 'ant-design-vue';
|
function fnHandleSubmit(values: any) {
|
validate()
|
.then((res) => {
|
if (!modelRef.subject) {
|
Modal.confirm({
|
title: '提示',
|
content: '邮件主题为空,确定要发送吗?',
|
onOk() {
|
pushSendingMail();
|
},
|
onCancel() {},
|
});
|
} else {
|
pushSendingMail();
|
}
|
})
|
.catch((error) => {
|
createMessage.error('表单验证失败');
|
});
|
}
|
import { useRouter } from 'vue-router';
|
const router = useRouter();
|
function pushSendingMail() {
|
const data = fnBuildingCommitData();
|
loading.value = true;
|
sendingMailApi(data)
|
.then((res) => {
|
loading.value = false;
|
if (res.code === 0) {
|
createMessage.success(res.msg);
|
router.push('/email/list');
|
}
|
})
|
.catch((error) => {
|
loading.value = false;
|
});
|
}
|
function fnPreview() {
|
router.push({ path: '/preview/index', query: { docCode: docCode.value } });
|
}
|
|
function fnSaveMailDrafts() {
|
const data = fnBuildingCommitData();
|
loading.value = true;
|
|
saveMailDraftsApi(data)
|
.then((res) => {
|
loading.value = false;
|
if (res.code == 0) {
|
docCode.value = res.data.docCode;
|
createMessage.success('保存成功');
|
}
|
})
|
.catch((error) => {
|
loading.value = false;
|
});
|
}
|
|
const fnSelectUser = (e) => {
|
modelRef[e.idName] = e.selectedRowKeys;
|
};
|
|
const userLength = computed(() => {
|
return (
|
modelRef.recipients.length + modelRef.ccRecipients.length + modelRef.bccRecipients.length
|
);
|
});
|
|
interface Recipient {
|
value: string;
|
email: string;
|
title: string;
|
}
|
|
const userParticulars = computed<Recipient | null>(() => {
|
const recipientId = modelRef.recipients?.[0];
|
if (!recipientId) {
|
console.error('Recipient ID is not defined.');
|
return { value: '', email: '', title: '' };
|
}
|
// 使用 find 方法查找匹配项
|
const foundItem = state.recipientsList.find((item) => item.email === recipientId);
|
|
// 返回找到的项,如果未找到则返回 null
|
return foundItem || { value: '', email: '', title: '' };
|
});
|
const fnHandleTimeZone = (e, type) => {
|
console.log('fnHandleTimeZone');
|
if (type == 'add') {
|
titleTimeZone.value = '添加';
|
typeTimeZone.value = 1;
|
} else {
|
titleTimeZone.value = '修改';
|
typeTimeZone.value = 2;
|
}
|
openTimeZone.value = true;
|
};
|
|
const openTimeZone = ref<boolean>(false);
|
const confirmLoading = ref<boolean>(false);
|
const titleTimeZone = ref<string>('添加');
|
const typeTimeZone = ref<number>(1);
|
|
const fnHandleTimeZoneOk = () => {
|
confirmLoading.value = true;
|
setTimeout(() => {
|
openTimeZone.value = false;
|
confirmLoading.value = false;
|
}, 2000);
|
};
|
|
function fnGetRecipientsList() {
|
emailListAPi({ key: '' }).then((body) => {
|
state.recipientsList = body.data;
|
});
|
}
|
// 邮箱校验正则表达式
|
const validateEmail = (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
import { debounce } from 'lodash-es';
|
let lastFetchId = 0;
|
|
const fetchUser = debounce((value) => {
|
lastFetchId += 1;
|
const fetchId = lastFetchId;
|
state.data = [];
|
state.fetching = true;
|
emailListAPi({ key: value }).then((body) => {
|
if (fetchId !== lastFetchId) {
|
// for fetch callback order
|
return;
|
}
|
|
state.recipientsList = body.data;
|
state.fetching = false;
|
});
|
}, 300);
|
|
// 回复
|
function fuGetReplyEmailData() {
|
getMailInfoApi({ docCode: router.currentRoute.value.query.docCode })
|
.then((res) => {
|
console.log(ref.data,'---3022');
|
modelRef.sender = res.data.receiver[0]
|
modelRef.recipients = [res.data.sender]
|
modelRef.subject = 'Re:'+ res.data.subject
|
modelRef.content = setContent(res.data)
|
// tableRowData.value = res.data;
|
})
|
.catch(() => {});
|
console.log('----------------4');
|
}
|
const setContent = (row) => {
|
const text = `<div style=\"font-size: 12px; font-family: Arial Narrow,serif; padding: 2px 0 2px 0;\">------------------ Original ------------------</div>\n<div style=\"font-size: 12px; background: #efefef; padding: 8px;\">\n<div><strong>From: </strong> ${row.sender} <<a style=\"color: #1e7bf9; text-decoration: none;\" href=\"mailto:${row.sender}\" target=\"_blank\" rel=\"noopener noreferrer\">${row.sender}</a>></div>\n<div><strong>Send time: </strong> ${row.createTime}</div>\n<div><strong>To: </strong> ${row.userName} <<a style=\"color: #1e7bf9; text-decoration: none;\" href=\"mailto:${row.receiver}\" target=\"_blank\" rel=\"noopener noreferrer\">${row.receiver}</a>></div>\n<div><strong>Subject: </strong> ${row.subject}</div>\n</div>`
|
return text + row.content
|
};
|
</script>
|
<style lang="less" scoped>
|
@prefix-cls: ~'@{namespace}-email';
|
.@{prefix-cls} {
|
.splitpanes__pane {
|
display: flex;
|
align-items: stretch;
|
justify-content: center;
|
// background-color: var(--component-background-color);
|
}
|
}
|
</style>
|