huangyinfeng
9 天以前 cb21a5aa46ecf7a58e3e6bee3fd7f3352ec909b5
邮件配置黑名单功能
1个文件已添加
4个文件已修改
528 ■■■■ 已修改文件
src/App.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/email/userList.ts 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/email/Utils/blacklist.vue 242 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/email/Utils/index.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/email/components/ListPage/drawerDetail.vue 244 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue
@@ -26,7 +26,7 @@
    // 先检查proxy是否存在,再进行操作
    if (proxy && proxy.$cookies) {
      proxy.$cookies.remove('JSESSIONID');
      proxy.$cookies.set('JSESSIONID', 'C7CD0C74AFDEF1C09705415FFD0E2299.jvm_59_9010', '1d');
      proxy.$cookies.set('JSESSIONID', '23542F948D2C450599CF5850631B432D.jvm_59_9010', '1d');
    } else {
      console.error('proxy对象未初始化或不包含$cookies属性');
    }
src/api/email/userList.ts
@@ -40,10 +40,14 @@
  DELETE_FOLDER = '/crm/mail/folder/deleteFolder.do',
  GET_FOLDER = '/crm/mail/folder/getFolder.do',
  GET_ROW_ID = '/getRowid.do',
  ADD_TAG = '/crm/mail/tag/addTag.do',
  ADD_TAG = '/crm/mail/blacklist/getBlackList.do',
  UPDATE_TAG = '/crm/mail/tag/updateTag.do',
  DELETE_TAG = '/crm/mail/tag/deleteTag.do',
  GET_TAG = '/crm/mail/tag/getTagList.do',
  ADD_BLACKLIST = '/crm/mail/blacklist/addBlackList.do',
  UPDATE_BLACKLIST = '/crm/mail/blacklist/updateBlackList.do',
  DELETE_BLACKLIST = '/crm/mail/blacklist/deleteBlackList.do',
  GET_BLACKLIST = '/crm/mail/blacklist/getBlackList.do',
}
// 获取邮件路由列表
export const getEmailModuleApi = () => defHttp.get({ url: Api.GET_EMAIL_MODULE });
@@ -246,3 +250,32 @@
    url: Api.GET_TAG,
    params,
  });
// 新增黑名单
export const addBlackListApi = (params) =>
  defHttp.post({
    url: Api.ADD_BLACKLIST,
    params,
  });
// 修改黑名单
export const updateBlackListApi = (params) =>
  defHttp.post({
    url: Api.UPDATE_BLACKLIST,
    params,
  });
// 删除黑名单
export const deleteBlackListApi = (params) =>
  defHttp.post({
    url: Api.DELETE_BLACKLIST,
    params,
  });
// 查询黑名单
export const getBlackListApi = (params) =>
  defHttp.get({
    url: Api.GET_BLACKLIST,
    params,
  });
src/views/email/Utils/blacklist.vue
New file
@@ -0,0 +1,242 @@
<template>
  <div class="p-2">
    <div>
      <vxe-toolbar>
        <template #buttons>
          <div style="display: flex; align-items: flex-end">
            <span style="font-size: 1.25rem; font-weight: 600">邮箱地址黑名单</span
            ><span style="margin-left: 5px; padding-bottom: 4px; font-size: 12px"
              >黑名单中邮箱对应的邮件将自动收取到垃圾邮件(不会收到新邮件提醒)</span
            >
          </div>
        </template>
        <template #tools>
          <a-button type="primary" @click="showModal('mail')">添加邮箱地址</a-button>
        </template>
      </vxe-toolbar>
      <a-input-search
        v-model:value="searchMail"
        placeholder="请输入关键字搜索"
        style="width: 300px; margin-bottom: 20px"
        @search="onSearch($event, 'mail')"
      />
      <a-table :columns="columns" :data-source="demo.mail" :scroll="{ y: 220 }" size="small">
        <template #bodyCell="{ column, record }">
          <template v-if="column.field == 'operate'">
            <a class="ant-dropdown-link" @click="fnDelete(record)">删除</a>
          </template>
          <template v-else-if="column.field == 'mail'">
            {{ record.blackContent }}
          </template>
        </template>
      </a-table>
    </div>
    <div>
      <vxe-toolbar>
        <template #buttons>
          <div style="display: flex; align-items: flex-end">
            <span style="font-size: 1.25rem; font-weight: 600">域名黑名单</span
            ><span style="margin-left: 5px; padding-bottom: 4px; font-size: 12px"
              >黑名单中域名对应的邮件将自动收取到垃圾邮件(不会收到新邮件提醒)</span
            >
          </div>
        </template>
        <template #tools>
          <a-button type="primary" @click="showModal('domainName')">添加域名</a-button>
        </template>
      </vxe-toolbar>
      <a-input-search
        v-model:value="searchDomainName"
        placeholder="请输入关键字搜索"
        style="width: 300px; margin-bottom: 20px"
        @search="onSearch($event, 'domainName')"
      />
      <a-table
        :columns="columnsDomainName"
        :data-source="demo.domain"
        :scroll="{ y: 220 }"
        size="small"
      >
        <template #bodyCell="{ column, record }">
          <template v-if="column.field == 'operate'">
            <a class="ant-dropdown-link" @click="fnDelete(record)">删除</a>
          </template>
          <template v-else-if="column.field == 'domainName'">
            {{ record.blackContent }}
          </template>
        </template>
      </a-table>
    </div>
    <a-modal :width="600" v-model:open="open" :title="`新建${formTypeName}黑名单`" @ok="handleOk">
      <a-form ref="formRef" :model="form" style="margin-top: 20px">
        <a-form-item
          v-if="formType === 'mail'"
          label="邮箱地址"
          name="blackContent"
          :rules="[{ required: true, type: 'email', message: '请输入邮箱地址', trigger: 'blur' }]"
        >
          <a-input v-model:value="form.blackContent" placeholder="请输入邮箱地址" />
        </a-form-item>
        <a-form-item
          v-else
          label="域名地址"
          name="blackContent"
          :rules="[{ required: true, validator: validatorDomainName }]"
        >
          <a-input v-model:value="form.blackContent" placeholder="请输入域名地址" />
        </a-form-item>
      </a-form>
    </a-modal>
  </div>
</template>
<script lang="ts" setup>
  import { ref, onMounted, onUnmounted, reactive } from 'vue';
  import { getBlackListApi, addBlackListApi, deleteBlackListApi } from '@/api/email/userList';
  onUnmounted(() => {});
  function fnGetList() {
    getBlackListApi({}).then((res) => {
      console.log(res);
      demo.mail = res.data.mail;
      demo.domain = res.data.domain;
    });
  }
  import { useMessage } from '@/hooks/web/useMessage';
  const { createMessage } = useMessage();
  const open = ref(false);
  const formRef = ref();
  const columns = [
    {
      title: '邮箱地址',
      field: 'mail',
      minWidth: 200,
    },
    {
      title: '操作',
      field: 'operate',
      width: 200,
    },
  ];
  const columnsDomainName = [
    {
      title: '域名地址',
      field: 'domainName',
      minWidth: 200,
    },
    {
      title: '操作',
      field: 'operate',
      width: 200,
    },
  ];
  function validatorDomainName(rule, value, callback) {
    if (!value) {
      callback(new Error('请输入域名地址'));
    } else {
      if (!/[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?/.test(value)) {
        callback(new Error('域名地址格式不正确!'));
      } else {
        callback();
      }
    }
  }
  const form = reactive({
    blackContent: '',
  });
  const formTypeName = ref('邮箱地址');
  const formType = ref('mail');
  const demo = reactive({
    mail: [],
    domain: [],
  });
  const searchMail = ref('');
  const searchDomainName = ref('');
  function showModal(blackType) {
    open.value = true;
    if (blackType === 'mail') {
      formTypeName.value = '邮箱地址';
      formType.value = 'mail';
    } else {
      formTypeName.value = '域名地址';
      formType.value = 'domainName';
    }
  }
  function handleOk() {
    formRef.value.validate().then(() => {
      addBlackListApi({
        blackContent: form.blackContent,
        blackType: formType.value === 'mail' ? false : true,
      }).then((res) => {
        createMessage.success('添加成功');
        open.value = false;
        fnGetList();
      });
    });
  }
  function fnDelete(row) {
    deleteBlackListApi({
      blackId: row.blackId,
    }).then((res) => {
      createMessage.success('删除成功');
      fnGetList();
    });
  }
function onSearch(e, type) {
    console.log(e, type,'---3333');
    const data = {
      search: e,
      type: type === 'mail' ? 0 : 1,
    };
    if (type === 'mail') {
      getBlackListApi(data).then((res) => {
        demo.mail = res.data.mail;
      });
    } else {
      getBlackListApi(data).then((res) => {
        demo.domain = res.data.domain;
      });
    }
  }
  onMounted(() => {
    fnGetList();
  });
</script>
<style scoped>
  .sortable-row-demo .drag-btn {
    font-size: 12px;
    cursor: move;
  }
  .sortable-row-demo .vxe-body--row.sortable-ghost,
  .sortable-row-demo .vxe-body--row.sortable-chosen {
    background-color: #dfecfb;
  }
  .bookmark {
    display: inline-block;
    position: relative;
    width: 14px;
    height: 18px;
    margin-right: 5px;
    border-radius: 2px 2px 0 0; /* Rounded top corners */
  }
  .bookmark::after {
    content: '';
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    height: 8px;
    background-color: #fff;
    clip-path: polygon(50% 60%, 0% 100%, 100% 100%); /* Triangle at the bottom */
  }
</style>
src/views/email/Utils/index.vue
@@ -12,7 +12,7 @@
      ></a-tab-pane>
      <a-tab-pane key="4" tab="文件夹"><Folder v-if="activeKey === '4'" /></a-tab-pane>
      <a-tab-pane key="5" tab="标签"><Label v-if="activeKey==='5'" /></a-tab-pane>
      <a-tab-pane key="6" tab="黑名单">Content of Tab Pane 3</a-tab-pane>
      <a-tab-pane key="6" tab="黑名单"><Blacklist v-if="activeKey === '6'" /></a-tab-pane>
    </a-tabs>
  </div>
</template>
@@ -25,6 +25,7 @@
  import Convention from './convention.vue';
  import QuickText from './quickText.vue';
  import Folder from './folder.vue';
  import Label from './label.vue';
import Label from './label.vue';
  import Blacklist from './blacklist.vue'
</script>
<style scoped lang="less"></style>
src/views/email/components/ListPage/drawerDetail.vue
@@ -2,31 +2,76 @@
  <a-drawer
    v-model:open="drawerOpen"
    :placement="placement"
    width="72%"
    width="1200"
    :body-style="{ paddingBottom: '80px' }"
    :footer-style="{ textAlign: 'right' }"
    @after-open-change="afterOpenChange"
    @close="drawerClose"
  >
    <template #title>
      <pageHeadLeft
        :checked="true"
        :selectAllRow="[{ docCode }]"
        @nextNum="drawerClose"
      ></pageHeadLeft>
      <div class="left">
          <span style="margin-right: 20px; font-size: 24px; font-weight: 700">
            <a-tooltip placement="bottom">
              <template #title>
                <span>{{ tableRowData.subject }}</span>
              </template>
              {{ truncateString(tableRowData.subject, 23) }}
            </a-tooltip>
          </span>
          <span style="margin-right: 10px; font-size: 16px">
            <PushpinOutlined />
          </span>
      <div class="ctb">
        <pageHeadLeft
          :checked="true"
          :selectAllRow="[{ docCode }]"
          @nextNum="drawerClose"
        ></pageHeadLeft>
      <div class="ct-top">
        <div class="title" style="margin-bottom: 20px">
          <div class="left">
            <span style="margin-right: 20px; font-size: 24px; font-weight: 700">
              <a-tooltip placement="bottom">
                <template #title>
                  <span>{{ tableRowData.subject }}</span>
                </template>
                {{ truncateString(tableRowData.subject, 23) }}
              </a-tooltip>
            </span>
            <span style="margin-right: 10px; font-size: 16px">
              <PushpinOutlined />
            </span>
          </div>
          <div class="right">
            <div class="tate">{{ formatToDateDay(tableRowData.receiveTime) }}</div>
            <div>
              <a-dropdown-button>
                <span>
                  <a-tooltip placement="bottom">
                    <template #title>
                      <span>回复</span>
                    </template>
                    <LeftOutlined @click="replyEmail(tableRowData)" />
                  </a-tooltip>
                </span>
                <a-divider type="vertical" />
                <span>
                  <a-tooltip placement="bottom">
                    <template #title>
                      <span>快速回复</span>
                    </template>
                    <DoubleLeftOutlined />
                  </a-tooltip>
                </span>
                <template #overlay>
                  <a-menu>
                    <a-menu-item key="1">
                      <UserOutlined />
                      1st menu item
                    </a-menu-item>
                    <a-menu-item key="2">
                      <UserOutlined />
                      2nd menu item
                    </a-menu-item>
                    <a-menu-item key="3">
                      <UserOutlined />
                      3rd item
                    </a-menu-item>
                  </a-menu>
                </template>
              </a-dropdown-button>
            </div>
          </div>
        </div>
      </div></div>
    </template>
    <template #extra>
      <div style="font-size: 16px">
@@ -35,46 +80,6 @@
        <LeftOutlined style="padding: 0 20px" @click="fnPrev" />
        <RightOutlined @click="fnNext" />
      </div>
      <div class="my-d-f">
          <div class="tate">{{ formatToDateDay(tableRowData.receiveTime) }}</div>
          <div>
            <a-dropdown-button>
              <span>
                <a-tooltip placement="bottom">
                  <template #title>
                    <span>回复</span>
                  </template>
                  <LeftOutlined @click="replyEmail(tableRowData)" />
                </a-tooltip>
              </span>
              <a-divider type="vertical" />
              <span>
                <a-tooltip placement="bottom">
                  <template #title>
                    <span>快速回复</span>
                  </template>
                  <DoubleLeftOutlined />
                </a-tooltip>
              </span>
              <template #overlay>
                <a-menu>
                  <a-menu-item key="1">
                    <UserOutlined />
                    1st menu item
                  </a-menu-item>
                  <a-menu-item key="2">
                    <UserOutlined />
                    2nd menu item
                  </a-menu-item>
                  <a-menu-item key="3">
                    <UserOutlined />
                    3rd item
                  </a-menu-item>
                </a-menu>
              </template>
            </a-dropdown-button>
          </div>
        </div>
    </template>
    <template #footer>
      <div style="display: flex">
@@ -87,65 +92,60 @@
          >发送
        </a-button>
      </div>
    </template>
    <div>
      <div class="title" style="margin-bottom: 20px">
      </div>
    </div>
    <div class="flex-between">
      <div class="ct-left p-2" :class="isOpen ? 'isOpen' : 'onOpen'">
        <div class="user p-1">
          <div style="display: flex; align-items: center">
            <a-avatar size="small" style="margin-right: 8px" src="#" />
            {{ tableRowData.sender }}
            <span>{{ `<${tableRowData.sender}>` }}</span>
            <span style="margin: 0 10px">发送</span>
            <a-popover placement="bottom">
              <template #content>
                <div
                  class="p-2"
                  style="
                    display: flex;
                    align-items: center;
                    border-bottom: 1px solid rgb(5 5 5 / 6%);
                  "
                >
                  <a-avatar size="small" style="margin-right: 8px" src="#" />
                  <span style="color: #000; font-weight: 700">
                    {{ `${tableRowData.receiver}` }}</span
                  >
                  <CopyOutlined />
                </div>
                <div class="display-flex p-2">
                  <a-button type="link" size="small">往来邮件</a-button>
                </div>
              </template>
      <div class="flex-between">
        <div class="ct-left p-2" :class="isOpen ? 'isOpen' : 'onOpen'">
          <div class="user p-1">
            <div style="display: flex; align-items: center">
              <a-avatar size="small" style="margin-right: 8px" src="#" />
              {{ `${tableRowData.receiver}` }}<span>{{ `<${tableRowData.receiver}>` }}</span>
            </a-popover>
          </div>
          <div
            type="info"
            class="p-2"
            style="margin-top: 10px; background-color: #e4f1ff; font-size: 14px"
          >
            <span>{{ `<${tableRowData.sender}>` }}</span>
            <span>暂未查询到该客户的当地时间</span>
            <!-- <span>2024-06-08 22:22</span> -->
          </div>
          <div class="ct" v-if="tableRowData.content">
            <TinymcePw ref="TinymcePwRef" v-model="tableRowData.content" />
              {{ tableRowData.sender }}
              <span>{{ `<${tableRowData.sender}>` }}</span>
              <span style="margin: 0 10px">发送</span>
              <a-popover placement="bottom">
                <template #content>
                  <div
                    class="p-2"
                    style="
                      display: flex;
                      align-items: center;
                      border-bottom: 1px solid rgb(5 5 5 / 6%);
                    "
                  >
                    <a-avatar size="small" style="margin-right: 8px" src="#" />
                    <span style="color: #000; font-weight: 700">
                      {{ `${tableRowData.receiver}` }}</span
                    >
                    <CopyOutlined />
                  </div>
                  <div class="display-flex p-2">
                    <a-button type="link" size="small">往来邮件</a-button>
                  </div>
                </template>
                <a-avatar size="small" style="margin-right: 8px" src="#" />
                {{ `${tableRowData.receiver}` }}<span>{{ `<${tableRowData.receiver}>` }}</span>
              </a-popover>
            </div>
            <div
              type="info"
              class="p-2"
              style="margin-top: 10px; background-color: #e4f1ff; font-size: 14px"
            >
              <span>{{ `<${tableRowData.sender}>` }}</span>
              <span>暂未查询到该客户的当地时间</span>
              <!-- <span>2024-06-08 22:22</span> -->
            </div>
            <div class="ct" v-if="tableRowData.content">
              <TinymcePw ref="TinymcePwRef" v-model="tableRowData.content" />
            </div>
          </div>
        </div>
        <div v-show="isOpen" class="ct-right p-2">sssss</div>
      </div>
      <div v-show="isOpen" class="ct-right p-2">sssss</div>
    </div>
    <div @click="fuToggleContent" class="toggle-btn" :class="isOpen ? 'onIconOpen' : 'iconOpen'">
      <LeftOutlined v-if="!isOpen" />
      <RightOutlined v-else />
      <div @click="fuToggleContent" class="toggle-btn" :class="isOpen ? 'onIconOpen' : 'iconOpen'">
        <LeftOutlined v-if="!isOpen" />
        <RightOutlined v-else />
      </div>
    </div>
  </a-drawer>
</template>
@@ -304,10 +304,10 @@
      }
    });
  }
  import {useRouter} from 'vue-router'
  import { useRouter } from 'vue-router';
  const router = useRouter();
  function replyEmail(row){
    router.push({ path: '/email/edit', query: { docCode: row.docCode,type: 'reply' } });
  function replyEmail(row) {
    router.push({ path: '/email/edit', query: { docCode: row.docCode, type: 'reply' } });
  }
</script>
@@ -362,7 +362,7 @@
  .flex-between {
    display: flex;
    margin-top: 4%;
    padding-top: 4%;
  }
  .ct-left {
@@ -403,4 +403,18 @@
  .onIconOpen {
    right: 32%;
  }
  .ctb {
    position: relative;
  }
  .ctb .ct-top {
    position: absolute;
    z-index: 99;
    top: 41px;
    left: -28px;
    width: 116%;
    padding: 10px;
    background: #fff;
  }
</style>