| | |
| | | // 先检查proxy是否存在,再进行操作 |
| | | if (proxy && proxy.$cookies) { |
| | | proxy.$cookies.remove('JSESSIONID'); |
| | | proxy.$cookies.set('JSESSIONID', '23542F948D2C450599CF5850631B432D.jvm_59_9010', '1d'); |
| | | proxy.$cookies.set('JSESSIONID', '741E9E2AAD7578915B16287A5ECAE1DF.jvm_59_9010', '1d'); |
| | | } else { |
| | | console.error('proxy对象未初始化或不包含$cookies属性'); |
| | | } |
| | |
| | | DELETE_FOLDER = '/crm/mail/folder/deleteFolder.do', |
| | | GET_FOLDER = '/crm/mail/folder/getFolder.do', |
| | | GET_ROW_ID = '/getRowid.do', |
| | | ADD_TAG = '/crm/mail/blacklist/getBlackList.do', |
| | | ADD_TAG = '/crm/mail/tag/addTag.do', |
| | | UPDATE_TAG = '/crm/mail/tag/updateTag.do', |
| | | DELETE_TAG = '/crm/mail/tag/deleteTag.do', |
| | | GET_TAG = '/crm/mail/tag/getTagList.do', |
| | |
| | | UPDATE_BLACKLIST = '/crm/mail/blacklist/updateBlackList.do', |
| | | DELETE_BLACKLIST = '/crm/mail/blacklist/deleteBlackList.do', |
| | | GET_BLACKLIST = '/crm/mail/blacklist/getBlackList.do', |
| | | GET_EMAIL_MODULE_BELOW = '/crm/mail/getEmailModuleBelow.do', |
| | | } |
| | | // 获取邮件路由列表 |
| | | export const getEmailModuleApi = () => defHttp.get({ url: Api.GET_EMAIL_MODULE }); |
| | |
| | | url: Api.GET_BLACKLIST, |
| | | params, |
| | | }); |
| | | |
| | | |
| | | export const getEmailModuleBelowApi = () => |
| | | defHttp.get({ |
| | | url: Api.GET_EMAIL_MODULE_BELOW, |
| | | }); |
| | | |
| | |
| | | button-style="solid" |
| | | size="small" |
| | | name="color" |
| | | @change="groupChange" |
| | | > |
| | | <a-radio-button |
| | | v-for="item in colors" |
| | |
| | | const props = defineProps({ |
| | | modelValue: { |
| | | type: String, |
| | | default:'#000000', |
| | | default: '#000000', |
| | | required: true, |
| | | }, |
| | | // 1普通,2选择器模式 |
| | |
| | | }); |
| | | |
| | | // 定义 emits,用于双向绑定 |
| | | const emit = defineEmits(['update:modelValue','change']); |
| | | const emit = defineEmits(['update:modelValue', 'change']); |
| | | |
| | | // 颜色选项 |
| | | const colors = ref([ |
| | |
| | | // 当本地值发生变化时,发出 update:modelValue 事件,通知父组件更新 |
| | | watch(localValue, (newValue) => { |
| | | emit('update:modelValue', newValue); |
| | | emit('change', newValue); |
| | | // emit('change', newValue); |
| | | }); |
| | | |
| | | function groupChange() { |
| | | console.log(localValue.value, '------------2'); |
| | | emit('change', localValue.value); |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | |
| | | height: 8px; |
| | | background-color: #fff; |
| | | clip-path: polygon(50% 60%, 0% 100%, 100% 100%); /* Triangle at the bottom */ |
| | | |
| | | } |
| | | </style> |
| | |
| | | import 'tinymce/plugins/image'; |
| | | import 'tinymce/plugins/table'; |
| | | import 'tinymce/plugins/charmap'; |
| | | import 'tinymce/plugins/imagetools'; |
| | | // import 'tinymce/plugins/imagetools'; |
| | | import 'tinymce/plugins/help'; |
| | | import 'tinymce/plugins/emoticons'; |
| | | import 'tinymce/plugins/emoticons/js/emojis'; |
| | |
| | | // import 'tinymce/plugins/tinyddrive'; |
| | | // import 'tinymce/plugins/advcode'; |
| | | // import 'tinymce/plugins/mediaembed'; |
| | | import 'tinymce/plugins/toc'; |
| | | // import 'tinymce/plugins/toc'; |
| | | // import 'tinymce/plugins/checklist'; |
| | | // import 'tinymce/plugins/tinycespellchecker'; |
| | | // import 'tinymce/plugins/a11ychecker'; |
| | |
| | | <template> |
| | | <div> |
| | | <PageWrapper :class="`${prefixCls}`" dense contentFullHeight fixedHeight> |
| | | <div class="default-theme" style="display: flex;height: 100%;background-color: #fff;"> |
| | | <div style="width: 10%;height: 100%;"> |
| | | <div class="default-theme" style="display: flex; height: 100%; background-color: #fff"> |
| | | <div style="width: 10%; height: 100%"> |
| | | <LeftNav></LeftNav> |
| | | </div> |
| | | <div style="width: 84%;height: 100%;"> |
| | | <div style="width: 84%; height: 100%"> |
| | | <RouterView> |
| | | <template #default="{ Component, route }"> |
| | | <transition |
| | |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import {PageWrapper} from '@/components/Page'; |
| | | import { Splitpanes, Pane } from 'splitpanes'; |
| | | import { PageWrapper } from '@/components/Page'; |
| | | import { Splitpanes, Pane } from 'splitpanes'; |
| | | |
| | | import LeftNav from '@/views/email/components/LeftNav.vue'; |
| | | import LeftNav from '@/views/email/components/LeftMenu/index.vue'; |
| | | import { computed, unref } from 'vue'; |
| | | |
| | | import FrameLayout from '@/layouts/iframe/index.vue'; |
| | |
| | | meta: { |
| | | title: '发件箱', |
| | | hideTab: true, |
| | | currentActiveMenu: '/email/index', |
| | | }, |
| | | children: [ |
| | | { |
| | | path: 'list', |
| | | name: 'Outbox', |
| | | name: 'IndexPage1', |
| | | component: () => import('@/views/email/outbox/index.vue'), |
| | | meta: { |
| | | title: '全部邮件', |
| | | currentActiveMenu: '/email/index', |
| | | title: '全部发件', |
| | | }, |
| | | }] |
| | | }, |
| | |
| | | meta: { |
| | | orderNo: 10, |
| | | icon: 'ion:grid-outline', |
| | | title: '邮件预览‘', |
| | | title: '邮件预览', |
| | | hideTab: true, |
| | | hideMenu: true, |
| | | }, |
| | | children: [ |
| | | { |
| | |
| | | <template> |
| | | <div> |
| | | <a-spin :spinning="loading" class="p-1" style="height: 100%"> |
| | | <PageIndex :pageList="pageList" :mailType="1" :pageData="pageData"> </PageIndex> |
| | | <PageIndex :pageList="pageList" :mailType="1" :pageData="pageData" :isDrafts='true'> </PageIndex> |
| | | </a-spin> |
| | | </div> |
| | | </template> |
| | |
| | | if (TYPE.value === 'reply') { |
| | | fuGetReplyEmailData(); |
| | | } |
| | | if (TYPE.value === 'edit') { |
| | | fuGetEditEmailData(); |
| | | } |
| | | }); |
| | | const useForm = Form.useForm; |
| | | const { validate, validateInfos } = useForm(modelRef, rulesRef); |
| | |
| | | sendingMailApi, |
| | | saveMailDraftsApi, |
| | | emailListAPi, |
| | | getMailInfoApi |
| | | getMailInfoApi, |
| | | } from '@/api/email/userList'; |
| | | // 定义状态管理对象 |
| | | const state = reactive({ |
| | |
| | | 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) |
| | | 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 |
| | | 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> |
| | |
| | | :row-config="{ keyField: 'id' }" |
| | | :column-config="{ resizable: true }" |
| | | :export-config="{}" |
| | | :tree-config="{ transform: true,rowField: 'rowId', parentField: 'parentRowId' }" |
| | | :tree-config="{ transform: true, rowField: 'rowId', parentField: 'parentRowId' }" |
| | | :edit-config="{ trigger: 'manual', mode: 'row' }" |
| | | height="600" |
| | | > |
| | |
| | | <vxe-column field="folderName" title="文件夹名称" minWidth="250" tree-node :edit-render="{}"> |
| | | <template #edit="{ row }"> |
| | | <vxe-input |
| | | :ref="el => inputRefs[row.id] = el" |
| | | :ref="(el) => (inputRefs[row.id] = el)" |
| | | v-model="row.folderName" |
| | | type="text" |
| | | style="width: 300px" |
| | |
| | | const currRow: Record<string, any> = demo.tableData.splice(oldIndex, 1)[0]; |
| | | // demo.tableData.splice(newIndex, 0, currRow); |
| | | updateFolderApi({ |
| | | textId: currRow.textId, |
| | | textName: currRow.textName, |
| | | content: currRow.content, |
| | | folderId: currRow.folderId, |
| | | folderName: currRow.folderName, |
| | | treeControl: currRow.treeControl, |
| | | parentRowId: currRow.parentRowId, |
| | | sortId: newIndex, |
| | | }) |
| | | .then(() => { |
| | |
| | | function fnGetList() { |
| | | getFolderApi({}).then((res) => { |
| | | console.log(res); |
| | | demo.tableData = res.data; |
| | | demo.tableData = convertToTableData(res.data); |
| | | console.log(demo.tableData, '3333333333333'); |
| | | }); |
| | | } |
| | | function convertToTableData(data, parentId = null) { |
| | | let tableData = []; |
| | | |
| | | data.forEach((item) => { |
| | | let tableItem = { |
| | | folderId: item.folderId, |
| | | parentRowId: parentId, |
| | | rowId: item.rowId, |
| | | folderName: item.folderName, |
| | | treeControl: item.treeControl, |
| | | }; |
| | | |
| | | if (item.list && item.list.length > 0) { |
| | | let children = convertToTableData(item.list, item.rowId); |
| | | tableData = tableData.concat(children); |
| | | } |
| | | |
| | | tableData.push(tableItem); |
| | | }); |
| | | return tableData; |
| | | } |
| | | |
| | | const inputRefs = ref<{ [key: number]: HTMLElement | null }>({}); |
| | |
| | | const { createMessage } = useMessage(); |
| | | function fnInputHandle(row) { |
| | | console.log(row, '----333'); |
| | | const data = { |
| | | folderName: row.folderName, |
| | | parentRowId: row.rowId, |
| | | }; |
| | | addFolderApi(data).then((res) => { |
| | | if (row.folderName == '') { |
| | | editRowEvent(row) |
| | | return createMessage.error('请输入文件夹名称'); |
| | | } |
| | | const data = |
| | | row.opType == 'edit' |
| | | ? { |
| | | folderId: row.folderId, |
| | | folderName: row.folderName, |
| | | treeControl: row.treeControl, |
| | | parentRowId: row.parentRowId, |
| | | sortId: row.sortId, |
| | | } |
| | | : { |
| | | folderName: row.folderName, |
| | | parentRowId: row.parentRowId, |
| | | }; |
| | | const api = row.opType == 'edit' ? updateFolderApi : addFolderApi; |
| | | const title = row.opType == 'edit' ? '编辑' : '添加'; |
| | | api(data).then((res) => { |
| | | if (res.code == 0) { |
| | | createMessage.success('添加成功'); |
| | | createMessage.success(`${title}成功`); |
| | | fnGetList(); |
| | | } else { |
| | | createMessage.error(res.msg); |
| | |
| | | id: rid, |
| | | parentRowId: row.rowId, // 需要指定父节点,自动插入该节点中 |
| | | }; |
| | | console.log(record, '99999993'); |
| | | const { row: newRow } = await $table.insert(record); |
| | | console.log(row,'99999993'); |
| | | |
| | | |
| | | await $table.setTreeExpand(row, true); // 将父节点展开 |
| | | await $table.setEditRow(newRow); // 插入子节点 |
| | | } |
| | |
| | | |
| | | function editRowEvent(row) { |
| | | const $table = xTable.value; |
| | | console.log(row,'---30494'); |
| | | |
| | | console.log(row, '---30494'); |
| | | row.opType = 'edit'; |
| | | $table.setEditRow(row); |
| | | } |
| | | onMounted(() => { |
| | |
| | | </div> |
| | | </template> |
| | | <template #tools> |
| | | <a-button type="primary" @click="showModal('add')">新建个人标签</a-button> |
| | | <a-button type="primary" @click="showModal('add','')">新建个人标签</a-button> |
| | | </template> |
| | | </vxe-toolbar> |
| | | |
| | |
| | | } |
| | | |
| | | function fnRowColorChange(color, row) { |
| | | console.log(color, row); |
| | | const data = { |
| | | tagColor: row.tagColor, |
| | | tagColor: color, |
| | | tagName: row.tagName, |
| | | tagType: row.tagType, |
| | | systemFlag: row.systemFlag, |
New file |
| | |
| | | <template> |
| | | <PageWrapper dense contentFullHeight fixedHeight> |
| | | <div> |
| | | <div class="header-container"> |
| | | <span class="button-group"> |
| | | <a-button shape="circle" size="large"> |
| | | <MailOutlined /> |
| | | </a-button> |
| | | <a-button shape="circle" size="large"> |
| | | <UserOutlined /> |
| | | </a-button> |
| | | </span> |
| | | <a-button |
| | | class="write-button" |
| | | type="primary" |
| | | size="large" |
| | | shape="round" |
| | | @click="$router.push('/email/edit')" |
| | | > |
| | | 写信 |
| | | </a-button> |
| | | </div> |
| | | |
| | | <div class="menu-container"> |
| | | <a-menu |
| | | id="email-left-nav" |
| | | v-model:open-keys="openKeys" |
| | | v-model:selected-keys="selectedKeys" |
| | | mode="inline" |
| | | :popupClassName="popupClassName" |
| | | > |
| | | <template v-for="item in menuItems" :key="item.key"> |
| | | <render-menu-item :item="item" @click="handleClick" /> |
| | | </template> |
| | | </a-menu> |
| | | <a-divider /> |
| | | <a-menu |
| | | id="email-left-nav2" |
| | | v-model:open-keys="openKeys" |
| | | v-model:selected-keys="selectedKeys" |
| | | mode="inline" |
| | | :popupClassName="popupClassName" |
| | | > |
| | | <template v-for="item in menuItems2" :key="item.key"> |
| | | <render-menu-item :item="item" @click="handleClick" /> |
| | | </template> |
| | | </a-menu> |
| | | </div> |
| | | </div> |
| | | </PageWrapper> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { ref, onMounted, computed } from 'vue'; |
| | | import { PageWrapper } from '@/components/Page'; |
| | | import { MailOutlined, UserOutlined } from '@ant-design/icons-vue'; |
| | | import { getEmailModuleApi, getEmailModuleBelowApi } from '@/api/email/userList'; |
| | | import { useRouter } from 'vue-router'; |
| | | |
| | | interface MenuItem { |
| | | key: string; |
| | | title: string; |
| | | total?: number; |
| | | children?: MenuItem[]; |
| | | } |
| | | |
| | | const selectedKeys = ref<string[]>(['Index']); |
| | | const openKeys = ref<string[]>(['Inbox']); |
| | | const items = ref<MenuItem[]>([]); |
| | | const items2 = ref<MenuItem[]>([]); |
| | | |
| | | const fetchEmailModules = async () => { |
| | | try { |
| | | const [res, res2] = await Promise.all([getEmailModuleApi(), getEmailModuleBelowApi()]); |
| | | items.value = convertRoutesToMenuItems(res.data); |
| | | items2.value = convertRoutesToMenuItems2(res2.data); |
| | | } catch (error) { |
| | | console.error('获取邮箱模块失败:', error); |
| | | } |
| | | }; |
| | | |
| | | const convertRoutesToMenuItems = (routes: any[]): MenuItem[] => { |
| | | return routes |
| | | .map(route => ({ |
| | | key: route.key, |
| | | title: route.mailName, |
| | | total: route.total, |
| | | children: route.children ? convertRoutesToMenuItems(route.children) : undefined, |
| | | })) |
| | | .filter(Boolean) as MenuItem[]; |
| | | }; |
| | | |
| | | const convertRoutesToMenuItems2 = (routes: any[]): MenuItem[] => { |
| | | return routes |
| | | .map(route => ({ |
| | | key: route.key, |
| | | title: route.name, |
| | | total: route.number, |
| | | children: route.list ? convertRoutesToMenuItems2(route.list) : undefined, |
| | | })) |
| | | .filter(Boolean) as MenuItem[]; |
| | | }; |
| | | |
| | | onMounted(fetchEmailModules); |
| | | |
| | | const routesConfig = { |
| | | InboxPage1: '/email/index', |
| | | receiver: '/email/Inbox/list', |
| | | sender: '/email/outbox/list', |
| | | IndexPage1: '/email/outbox', |
| | | }; |
| | | |
| | | const router = useRouter(); |
| | | const handleClick = (item: MenuItem) => { |
| | | const routePath = routesConfig[item.key] || router.getRoutes().find(r => r.name === item.key)?.path; |
| | | if (routePath) { |
| | | router.push(routePath); |
| | | } else { |
| | | console.warn(`Unknown key: ${item.key}`); |
| | | } |
| | | }; |
| | | |
| | | const popupClassName = { |
| | | display: 'flex', |
| | | 'align-items': 'center', |
| | | 'justify-content': 'space-between', |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .header-container { |
| | | height: 15vh; |
| | | padding: 20px 40px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .button-group { |
| | | display: flex; |
| | | justify-content: space-around; |
| | | } |
| | | |
| | | .write-button { |
| | | width: 100%; |
| | | margin-top: 10px; |
| | | padding: 0 30px; |
| | | } |
| | | |
| | | .menu-container { |
| | | height: 70vh; |
| | | overflow: auto; |
| | | } |
| | | |
| | | .my-display { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .my-left { |
| | | margin-left: 5px; |
| | | } |
| | | </style> |
| | |
| | | row: Object, // 当前行对象 |
| | | docCodeS: Array, |
| | | }); |
| | | console.log(props,'-59585855'); |
| | | |
| | | const emit = defineEmits(['updateHandleTime', 'completeAction', 'customTimeSubmit', 'tagRow']); |
| | | |
| | |
| | | <a-drawer |
| | | v-model:open="drawerOpen" |
| | | :placement="placement" |
| | | width="1200" |
| | | width="68%" |
| | | :body-style="{ paddingBottom: '80px' }" |
| | | :footer-style="{ textAlign: 'right' }" |
| | | @after-open-change="afterOpenChange" |
| | | @close="drawerClose" |
| | | > |
| | | <template #title> |
| | | <div class="ctb"> |
| | | <div> |
| | | <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> |
| | | </div> |
| | | </template> |
| | | <template #extra> |
| | | <div style="font-size: 16px"> |
| | |
| | | </a-button> |
| | | </div> |
| | | </template> |
| | | <div class="ct-top" :class="isOpen ? 'isOpenTop' : 'onOpenTop'"> |
| | | <div class="title"> |
| | | <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> |
| | | <div :style="{ maxWidth: isOpen ? '300px' : '600px' }" class="text-ellipsis">{{ |
| | | tableRowData.subject |
| | | }}</div> |
| | | </a-tooltip> |
| | | </span> |
| | | <span style="margin-right: 10px; font-size: 16px"> |
| | | <PushpinOutlined /> |
| | | </span> |
| | | </div> |
| | | <div class="right"> |
| | | <div class="tate">{{ formatToDateDay(tableRowData.receiveTime || tableRowData.updateTime) }}</div> |
| | | <div> |
| | | <a-dropdown-button> |
| | | <div v-if="!isDrafts"> |
| | | <span> |
| | | <a-tooltip placement="bottom"> |
| | | <template #title> |
| | | <span>回复</span> |
| | | </template> |
| | | <LeftOutlined @click="replyEmail(tableRowData, 'reply')" /> |
| | | </a-tooltip> |
| | | </span> |
| | | <a-divider type="vertical" /> |
| | | <span> |
| | | <a-tooltip placement="bottom"> |
| | | <template #title> |
| | | <span>快速回复</span> |
| | | </template> |
| | | <DoubleLeftOutlined /> |
| | | </a-tooltip> |
| | | </span> |
| | | </div> |
| | | <div v-else> |
| | | <span @click="replyEmail(tableRowData, 'edit')">再次编辑</span> |
| | | </div> |
| | | |
| | | <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> |
| | | <div class="flex-between"> |
| | | <div class="ct-left p-2" :class="isOpen ? 'isOpen' : 'onOpen'"> |
| | | <div class="user p-1"> |
| | | <div class="user p-1 f-z-14" style="margin-top: 40px"> |
| | | <div style="display: flex; align-items: center"> |
| | | <a-avatar size="small" style="margin-right: 8px" src="#" /> |
| | | {{ tableRowData.sender }} |
| | | <span>{{ `<${tableRowData.sender}>` }}</span> |
| | | <div> |
| | | <span>{{ tableRowData.senderName }} {{ `<${tableRowData.sender}>` }}</span> |
| | | </div> |
| | | <span style="margin: 0 10px">发送</span> |
| | | <a-popover placement="bottom"> |
| | | <template #content> |
| | |
| | | {{ `${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" |
| | | > |
| | | <div type="info" class="p-2 f-z-14" style="margin-top: 10px; background-color: #e4f1ff"> |
| | | <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 class="ct"> |
| | | <div v-if="tableRowData.content"> |
| | | <TinymcePw ref="TinymcePwRef" v-model="tableRowData.content" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div v-show="isOpen" class="ct-right p-2">sssss</div> |
| | | <div v-show="isOpen" class="ct-right"> |
| | | <div style="position: relative"> |
| | | <div style="position: absolute; top: 0; left: 10px"> |
| | | <UserTips></UserTips> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div @click="fuToggleContent" class="toggle-btn" :class="isOpen ? 'onIconOpen' : 'iconOpen'"> |
| | | <LeftOutlined v-if="!isOpen" /> |
| | |
| | | RollbackOutlined, |
| | | } from '@ant-design/icons-vue'; |
| | | import pageHeadLeft from './pageHeadLeft.vue'; |
| | | import UserTips from '@/views/email/components/userTips/index.vue'; |
| | | import { TinymcePw } from '@/components/Tinymce'; |
| | | import { getMailInfoApi, setQuickReplyAPi } from '@/api/email/userList'; |
| | | import { useCollapseStore } from '@/store/modules/useCollapseStore'; |
| | |
| | | mailId?: string; |
| | | selectAllRow: Array<any>; |
| | | allList; |
| | | isDrafts?: boolean; |
| | | } |
| | | |
| | | const props = defineProps<Props>(); |
| | |
| | | watch( |
| | | () => props.modelValue, |
| | | (newValue) => { |
| | | drawerOpen.value = newValue; |
| | | nextTick(() => { |
| | | console.log(newValue, '---------4', TinymcePwRef.value); |
| | | drawerOpen.value = newValue; |
| | | setTimeout(() => { |
| | | console.log(newValue, '---------4', TinymcePwRef.value); |
| | | tableRowData.value.content = tableRowData.value.content; |
| | | }, 500); |
| | | }); |
| | | if (newValue) { |
| | | fnGetMailInfo(props.mailId); |
| | |
| | | function fnGetMailInfo(id) { |
| | | getMailInfoApi({ docCode: id }) |
| | | .then((res) => { |
| | | docCode.value = id; |
| | | tableRowData.value = res.data; |
| | | nextTick(() => { |
| | | docCode.value = id; |
| | | tableRowData.value = res.data; |
| | | }); |
| | | }) |
| | | .catch(() => {}); |
| | | } |
| | |
| | | drawerOpen.value = false; |
| | | }; |
| | | |
| | | function truncateString(str, maxLength) { |
| | | return str.length > maxLength ? str.substring(0, maxLength) + '...' : str; |
| | | } |
| | | |
| | | const fnGetUserList = (params) => { |
| | | // 调用接口逻辑 |
| | | }; |
| | | |
| | | // 计算属性 |
| | | const placement = computed(() => props.placement || 'right'); |
| | | |
| | | // 抽屉开关 |
| | | const fnSaveOpenChange = () => { |
| | | // 抽屉保存逻辑 |
| | | }; |
| | | |
| | | const content = ref(''); |
| | | const isOpen = ref(false); |
| | |
| | | } |
| | | 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, type) { |
| | | router.push({ path: '/email/edit', query: { docCode: row.docCode, type: type } }); |
| | | } |
| | | </script> |
| | | |
| | |
| | | |
| | | & .right { |
| | | display: flex; |
| | | flex: 1; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | width: 25%; |
| | | justify-content: flex-end; |
| | | |
| | | & .tate { |
| | | color: #999; |
| | | font-size: 14px; |
| | | margin-right: 10px; |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | .flex-between { |
| | | display: flex; |
| | | padding-top: 4%; |
| | | } |
| | | |
| | | .ct-left { |
| | |
| | | } |
| | | |
| | | .ct-right { |
| | | border-left: 1px solid #f0f0f0; |
| | | flex: 1; |
| | | } |
| | | |
| | | .toggle-btn { |
| | |
| | | } |
| | | |
| | | .isOpen { |
| | | width: 69%; |
| | | width: calc(100% - 420px); |
| | | } |
| | | |
| | | .onOpenTop { |
| | | width: 98%; |
| | | } |
| | | |
| | | .isOpenTop { |
| | | width: calc(98% - 460px); |
| | | } |
| | | |
| | | .iconOpen { |
| | |
| | | } |
| | | |
| | | .onIconOpen { |
| | | right: 32%; |
| | | right: 425px; |
| | | } |
| | | |
| | | .ctb { |
| | | position: relative; |
| | | } |
| | | |
| | | .ctb .ct-top { |
| | | .ct-top { |
| | | position: absolute; |
| | | z-index: 99; |
| | | top: 41px; |
| | | left: -28px; |
| | | width: 116%; |
| | | top: 57px; |
| | | left: 10px; |
| | | padding: 10px; |
| | | background: #fff; |
| | | } |
| | | |
| | | .text-ellipsis { |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .f-z-14 { |
| | | font-size: 12px; |
| | | } |
| | | </style> |
| | |
| | | </a-switch> |
| | | </div> |
| | | </div> |
| | | <div v-if="checked" class="left-bt p-3"> |
| | | <div v-if="checked" style="height: 30px;" class="left-bt p-3"> |
| | | 已选择此页面上所有 20 封邮件 , 选择全部 335 封邮件 |
| | | </div> |
| | | <div class="p-4" style="height: 90%; overflow: hidden"> |
| | |
| | | ref="tableRef" |
| | | :page="pageCurrent" |
| | | :pageList="newList" |
| | | :isDrafts="isDrafts" |
| | | @selectAll="fnSelectAll" |
| | | @updateSelectAll="updateSelectAll" |
| | | /> |
| | |
| | | // 定义属性 |
| | | interface Props { |
| | | pageList?: []; |
| | | pageData?:any; |
| | | pageData?: any; |
| | | mailType?: number; |
| | | isDrafts?: boolean; |
| | | } |
| | | const props = defineProps<Props>(); |
| | | const newList = ref([]); |
| | |
| | | </template> |
| | | <a-dropdown :arrow="{ pointAtCenter: true }" placement="bottom" :trigger="['click']"> |
| | | <template #overlay> |
| | | <a-menu> |
| | | <a-menu v-if="checked"> |
| | | <a-menu-item key="2" @click="fnSelectAllRead(true)"> 标为已读</a-menu-item> |
| | | <a-menu-item key="3" @click="fnSelectAllRead(false)"> 标为未读</a-menu-item> |
| | | <a-menu-item key="4"> 设为置顶</a-menu-item> |
| | | <a-divider style="margin: 2px; padding: 2px" /> |
| | | <a-menu-item key="5"> 标记为垃圾邮件</a-menu-item> |
| | | </a-menu> |
| | | </template> |
| | | <MoreOutlined v-show="checked" class="icon" /> |
| | | <!-- </template> |
| | | <MoreOutlined v-if="checked" class="icon" /> |
| | | </a-dropdown> |
| | | <a-dropdown :arrow="{ pointAtCenter: true }" placement="bottom" :trigger="['click']"> |
| | | <template #overlay> |
| | | <a-menu> |
| | | <template #overlay> --> |
| | | <a-menu v-else> |
| | | <a-menu-item key="1" @click="fnAllRead">全部标记为已读</a-menu-item> |
| | | <a-divider style="margin: 2px; padding: 2px" /> |
| | | <p style="color: #999; font-size: 12px">勾选邮件即可查看更多操作</p> |
| | | </a-menu> |
| | | </template> |
| | | <MoreOutlined v-show="!checked" class="icon" /> |
| | | <MoreOutlined class="icon" /> |
| | | </a-dropdown> |
| | | </a-tooltip> |
| | | </div> |
| | |
| | | pushUpdateReadApi(data); |
| | | } |
| | | const getSelectAllBocCode = computed(() => { |
| | | let data = props.selectAllRow.map((item) => item.docCode); |
| | | console.log(data, '00003'); |
| | | try { |
| | | if (props.parentTableList?.length == 0) { |
| | | return []; |
| | | } |
| | | let data = props.selectAllRow.map((item) => item.docCode); |
| | | console.log(data, '00003'); |
| | | |
| | | return data; |
| | | return data; |
| | | } catch (error) { |
| | | return []; |
| | | } |
| | | }); |
| | | function pushUpdateReadApi(data) { |
| | | updateReadApi(data).then((res) => { |
| | |
| | | pushUpdateReadApi(data); |
| | | } |
| | | function getReadId() { |
| | | const ids = []; |
| | | props.parentTableList.forEach((item: Record<string, any>) => { |
| | | ids.push(item.docCode); |
| | | }); |
| | | return ids; |
| | | try { |
| | | const ids = []; |
| | | if (props.parentTableList?.length == 0) { |
| | | return []; |
| | | } |
| | | props.parentTableList.forEach((item: Record<string, any>) => { |
| | | ids.push(item.docCode); |
| | | }); |
| | | return ids; |
| | | } catch (error) { |
| | | return []; |
| | | } |
| | | } |
| | | const emit = defineEmits(['nextNum']); |
| | | function fuDeleteEmail() { |
| | |
| | | <div |
| | | v-if="row.mailType != 0" |
| | | class="dot" |
| | | :class="row.readFlag ? 'dot-color' : ''" |
| | | :class="fnIsItHighlighted(row) ? 'dot-color' : ''" |
| | | @click.stop="fnRowUpdateRead(row)" |
| | | ></div> |
| | | <a-tooltip placement="bottom"> |
| | |
| | | > |
| | | <a-avatar size="small" style="margin-right: 8px" :src="row.avatar" /> |
| | | <span style="color: #000; font-weight: 700">{{ row.sender }}</span> |
| | | <CopyOutlined /> |
| | | <CopyOutlined @click="copyText(row.sender)" /> |
| | | </div> |
| | | <div class="display-flex p-2"> |
| | | <a-button type="link" size="small">新建客户</a-button> |
| | |
| | | <a-button type="link" size="small">往来邮件</a-button></div |
| | | > |
| | | </template> |
| | | <div class="title-dot" :class="row.readFlag ? 'title-dot-color' : ''"> |
| | | <div class="title-dot" :class="fnIsItHighlighted(row) ? 'title-dot-color' : ''"> |
| | | <span style="font-weight: 700">{{ row.senderName }}</span |
| | | ><span style="padding: 0 8px">|</span> |
| | | <span style="font-weight: 500">{{ row.sender }}</span> |
| | |
| | | <template #default="{ row }"> |
| | | <span |
| | | class="title-dot" |
| | | :class="row.readFlag ? 'title-dot-color' : ''" |
| | | :class="fnIsItHighlighted(row) ? 'title-dot-color' : ''" |
| | | style="font-weight: 500" |
| | | >{{ row.subject || '(无主题)' }}</span |
| | | > |
| | |
| | | </span> |
| | | </template> |
| | | </vxe-column> |
| | | </vxe-table> |
| | | </div |
| | | </vxe-table> </div |
| | | ></div> |
| | | |
| | | <div v-else style="height: 70vh; display: flex; align-items: center; justify-content: center"> |
| | | <div v-else style="display: flex; align-items: center; justify-content: center; height: 70vh"> |
| | | <a-empty /> |
| | | </div> |
| | | <DrawerDetail |
| | |
| | | :mailId="rowMailId" |
| | | :selectAllRow="selectRow" |
| | | :allList="dataSource" |
| | | :isDrafts="isDrafts" |
| | | /> |
| | | <a-dropdown :trigger="['click']" placement="bottomLeft" ref="dropdownRefs"> </a-dropdown> |
| | | </div> |
| | |
| | | // 定义属性 |
| | | interface Props { |
| | | pageList: []; |
| | | isDrafts?: boolean; |
| | | } |
| | | const props = defineProps<Props>(); |
| | | |
| | |
| | | } |
| | | } |
| | | const vxeTableRef = ref(); |
| | | function fnIsItHighlighted(row) { |
| | | return row.readFlag && props.isDrafts; |
| | | } |
| | | function fnSelectAll(is) { |
| | | vxeTableRef.value.forEach((row) => { |
| | | row.setAllCheckboxRow(is); |
| | | }); |
| | | selectChangeEvent(); |
| | | try { |
| | | if (!vxeTableRef.value) { |
| | | return; |
| | | } |
| | | vxeTableRef.value.forEach((row) => { |
| | | row.setAllCheckboxRow(is); |
| | | }); |
| | | selectChangeEvent(); |
| | | } catch (error) { |
| | | console.log(error); |
| | | } |
| | | } |
| | | |
| | | function selectChangeEvent() { |
| | |
| | | selectRow.value = []; |
| | | rowMailId.value = event.row.docCode; |
| | | selectRow.value.push({ docCode: event.row.docCode }); |
| | | fnRowUpdateRead(event.row); |
| | | openDrawerDetail.value = true; |
| | | }; |
| | | |
| | | // 更新祖父组件数据 |
| | | const getDataList = inject('getDataList'); |
| | | console.log(getDataList, '0000004'); |
| | | |
| | | import { updateReadApi, updateHandleAPi } from '@/api/email/userList'; |
| | | // 标志未读/经读 |
| | |
| | | } |
| | | }); |
| | | } |
| | | import { useMessage } from '@/hooks/web/useMessage'; |
| | | |
| | | const { createMessage } = useMessage(); |
| | | const copyText = async (value) => { |
| | | try { |
| | | await navigator.clipboard.writeText(value); |
| | | setTimeout(() => { |
| | | createMessage.success('复制成功'); |
| | | }, 500); |
| | | } catch (err) { |
| | | console.error('复制失败: ', err); |
| | | } |
| | | }; |
| | | const emit = defineEmits(['selectAll', 'updateSelectAll']); |
| | | defineExpose({ |
| | | fnSelectAll, |
New file |
| | |
| | | <template> |
| | | <a-layout class="p-2" style="width: 420px; background-color: #fff"> |
| | | <div :style="headerStyle"> |
| | | <div class="my-d-f"> |
| | | <a-avatar style="margin-right: 8px" src="#" /> |
| | | <div> |
| | | <div style="color: #000; font-weight: 700">XXX</div> |
| | | <div style="color: #000"> 124404189@qq.com </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <a-layout-content> |
| | | <a-tabs v-model:activeKey="activeKey" class="m-t-4"> |
| | | <a-tab-pane key="1" tab="客户画像"> |
| | | <div class="tabs-bk p-2" v-if="activeKey === '1'">sssssssssssssss</div> |
| | | </a-tab-pane> |
| | | <a-tab-pane key="2" tab="建档建议" force-render> |
| | | <div class="tabs-bk p-2" v-if="activeKey === '2'"></div> |
| | | </a-tab-pane> |
| | | <a-tab-pane key="3" tab="谈单指南" |
| | | ><div class="tabs-bk p-2" v-if="activeKey === '3'"></div |
| | | ></a-tab-pane> |
| | | <a-tab-pane key="4" tab="文档记录" |
| | | ><div class="tabs-bk p-2" v-if="activeKey === '4'" |
| | | /></a-tab-pane> |
| | | <a-tab-pane key="5" tab="物流查价" |
| | | ><div class="tabs-bk p-2" v-if="activeKey === '5'" |
| | | /></a-tab-pane> |
| | | <a-tab-pane key="6" tab="往来邮件" |
| | | ><div class="tabs-bk p-2" v-if="activeKey === '6'" |
| | | /></a-tab-pane> |
| | | <a-tab-pane key="6" tab="Tips" |
| | | ><div class="tabs-bk p-2" v-if="activeKey === '6'" |
| | | /></a-tab-pane> |
| | | </a-tabs> |
| | | </a-layout-content> |
| | | </a-layout> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | name: 'Utils'; |
| | | import { ref } from 'vue'; |
| | | const headerStyle = { |
| | | color: '#fff', |
| | | height: 104, |
| | | paddingInline: 50, |
| | | backgroundColor: '#fff', |
| | | }; |
| | | const activeKey = ref('1'); |
| | | </script> |
| | | <style scoped lang="less"> |
| | | .tabs-bk { |
| | | height: 60vh; |
| | | background-color: #fafafa; |
| | | } |
| | | |
| | | |
| | | .vxe-tabs-header--bar { |
| | | border: 0 solid transparent; |
| | | } |
| | | </style> |
| | |
| | | |
| | | <script lang="ts" setup> |
| | | import { PageWrapper } from '@/components/Page'; |
| | | import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue'; |
| | | import LeftNav from '@/views/email/components/LeftNav.vue'; |
| | | import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue'; |
| | | import LeftNav from '@/views/email/components/LeftMenu/index.vue'; |
| | | import { computed, unref, ref } from 'vue'; |
| | | |
| | | import FrameLayout from '@/layouts/iframe/index.vue'; |
| | |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | name: 'outbox'; |
| | | name: 'IndexPage1'; |
| | | import { ref, onMounted, computed, provide } from 'vue'; |
| | | import PageIndex from '@/views/email/components/ListPage/list.vue'; |
| | | import { useRoute } from 'vue-router'; |