huangyinfeng
4 天以前 db42d08c39ae6129e2b95cd24c0d57c6769282e5
src/views/email/Edit/index.vue
@@ -1,242 +1,262 @@
<template>
    <a-card size="small">
      <div 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
  <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"
              >
              <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: 'name', value: 'id' }"
              :options="state.data"
              :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="multiple"
                  show-search
                  placeholder="请选择收件人或者输入收件人邮箱"
                  v-model:value="modelRef.recipients"
                  :options="state.data"
                  :field-names="{ label: 'name', value: 'id' }"
                  :maxTagCount="4"
                  :filter-option="fnFilterOption"
                />
              </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)"
                <template #tagRender="{ label, closable, onClose, option }">
                  <a-tag
                    :closable="closable"
                    style="margin-right: 3px"
                    @close="onClose"
                    :color="validateEmail(label) ? 'default' : 'red'"
                  >
                    {{ !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.name}<${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>
                    {{ label }}&nbsp;&nbsp;
                  </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-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="multiple"
                  show-search
                  placeholder="请选择抄送人或者输入抄送人邮箱"
                  v-model:value="modelRef.ccRecipients"
                  :options="state.data"
                  :field-names="{ label: 'name', value: 'id' }"
                  :maxTagCount="4"
                  :filter-option="fnFilterOption"
                />
              </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="multiple"
                  show-search
                  placeholder="请选择抄送人或者输入抄送人邮箱"
                  v-model:value="modelRef.bccRecipients"
                  :options="state.data"
                  :field-names="{ label: 'name', value: 'id' }"
                  :maxTagCount="4"
                  :filter-option="fnFilterOption"
                />
              </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 @change="fnChangeContent"></Tinymce>
          </a-form-item>
        </a-form>
      </div>
      <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>
    </a-card>
          <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 }}&nbsp;&nbsp;
                  </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 }}&nbsp;&nbsp;
                  </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'
  name: 'Edit';
  import { useDesign } from '@/hooks/web/useDesign';
  import { ref, reactive, computed } from 'vue';
  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';
@@ -247,10 +267,11 @@
    recipients: [],
    ccRecipients: [],
    bccRecipients: [],
    fileUNID: [],
    attachmentList: [],
    subject: '',
    content: '',
  });
  const loading = ref(false);
  const rulesRef = reactive({
    sender: [
      {
@@ -270,6 +291,18 @@
        message: '内容不能为空',
      },
    ],
  });
  const TYPE = computed(() => {
    return router.currentRoute.value.query.type || 'send';
  });
  onMounted(() => {
    fnGetRecipientsList();
    if (TYPE.value === 'reply') {
      fuGetReplyEmailData();
    }
    if (TYPE.value === 'edit') {
      fuGetEditEmailData();
    }
  });
  const useForm = Form.useForm;
  const { validate, validateInfos } = useForm(modelRef, rulesRef);
@@ -291,22 +324,31 @@
  };
  const { createMessage } = useMessage();
  import { getUserListApi, sendingMailApi, saveMailDraftsApi } from '@/api/email/userList';
  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 getUserListApi(params);
      const res = await getAccountListApi();
      console.log(res, 'res');
      if (res && res.items && Array.isArray(res.items)) {
        state.data = res.items;
      if (res && res.data && Array.isArray(res.data)) {
        state.senderList = res.data;
      } else {
        console.error('Invalid response format:', res);
      }
@@ -326,7 +368,7 @@
  fetchData();
  const fnFilterOption = (input: string, option: any) => {
    return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
    return option.email.toLowerCase().indexOf(input.toLowerCase()) >= 0;
  };
  const openSelectUser = ref(false);
@@ -351,9 +393,47 @@
  };
  function fnChangeContent(e) {
    modelRef.content = e.content;
    modelRef.fileUNID = e.fileUNID;
  if (!isValidEvent(e)) {
    console.error('Invalid event:', e);
    return;
  }
  console.log('Event:', e, '----------------');
  modelRef.content = e.content;
  modelRef.attachmentList = mergeArrayWithPrefix(fnBuildAttachmentList(e.fileUNID));
  console.log('Updated modelRef:', modelRef);
}
function isValidEvent(e) {
  return e && typeof e === 'object' && typeof e.content === 'string';
}
function fnBuildAttachmentList(data) {
  if (!Array.isArray(data)) {
    console.error('Invalid argument: data must be an array');
    return [];
  }
  return data.reduce((acc, item) => {
    const uuid = item?.response?.uuid;
    if (uuid) {
      acc.push(uuid);
    } else {
      console.warn('Invalid item:', item);
    }
    return acc;
  }, []);
}
function mergeArrayWithPrefix(arr) {
  if (!arr || arr.length === 0) return '';
  const [prefix] = arr[0].split(';');
  const suffixes = arr.map(item => item.split(';')[1]).filter(Boolean).join(';');
  return `${prefix};${suffixes}`;
}
  function fnBuildingCommitData() {
    return {
@@ -363,7 +443,7 @@
      bcc: modelRef.bccRecipients,
      subject: modelRef.subject,
      content: modelRef.content,
      fileUNID: '4DFEFEB4-3BB1-448D-9712-DC6C106A7A44;7732',
      attachmentList: modelRef.attachmentList,
      docCode: docCode.value,
    };
  }
@@ -389,19 +469,42 @@
        createMessage.error('表单验证失败');
      });
  }
  import { useRouter } from 'vue-router';
  const router = useRouter();
  function pushSendingMail() {
    const data = fnBuildingCommitData();
    sendingMailApi(data).then((res) => {});
    loading.value = true;
    sendingMailApi(data)
      .then((res) => {
        loading.value = false;
        if (res.code === 0) {
          createMessage.success(res.msg);
          router.push('/email/index');
        }
      })
      .catch((error) => {
        loading.value = false;
      });
  }
  function fnPreview() {}
  function fnPreview() {
    router.push({ path: '/preview/index', query: { docCode: docCode.value } });
  }
  function fnSaveMailDrafts() {
    const data = fnBuildingCommitData();
    saveMailDraftsApi(data).then((res) => {
      docCode.value = res.data.docCode;
      createMessage.success(res.msg);
    });
    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) => {
@@ -427,7 +530,7 @@
      return { value: '', email: '', title: '' };
    }
    // 使用 find 方法查找匹配项
    const foundItem = state.data.find((item) => item.id === recipientId);
    const foundItem = state.recipientsList.find((item) => item.email === recipientId);
    // 返回找到的项,如果未找到则返回 null
    return foundItem || { value: '', email: '', title: '' };
@@ -456,7 +559,62 @@
      confirmLoading.value = false;
    }, 2000);
  };
  const { prefixCls } = useDesign('email');
  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 fuGetEditEmailData() {
    getMailInfoApi({ docCode: router.currentRoute.value.query.docCode })
      .then((res) => {
        modelRef.sender = res.data.sender;
        modelRef.recipients = res.data.receiver;
        modelRef.subject = res.data.subject;
        modelRef.content = res.data.content;
      })
      .catch(() => {});
  }
  // 回复
  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;\">------------------&nbsp;Original&nbsp;------------------</div>\n<div style=\"font-size: 12px; background: #efefef; padding: 8px;\">\n<div><strong>From:&nbsp;</strong>&nbsp;${row.sender} &lt;<a style=\"color: #1e7bf9; text-decoration: none;\" href=\"mailto:${row.sender}\" target=\"_blank\" rel=\"noopener noreferrer\">${row.sender}</a>&gt;</div>\n<div><strong>Send time:&nbsp;</strong>&nbsp;${row.createTime}</div>\n<div><strong>To:&nbsp;</strong>&nbsp;${row.userName} &lt;<a style=\"color: #1e7bf9; text-decoration: none;\" href=\"mailto:${row.receiver}\" target=\"_blank\" rel=\"noopener noreferrer\">${row.receiver}</a>&gt;</div>\n<div><strong>Subject:&nbsp;</strong> ${row.subject}</div>\n</div>`;
    return text + row.content;
  };
</script>
<style lang="less" scoped>
  @prefix-cls: ~'@{namespace}-email';