| | |
| | | :body-style="{ paddingBottom: '80px' }" |
| | | :footer-style="{ textAlign: 'right' }" |
| | | @after-open-change="afterOpenChange" |
| | | @close="close" |
| | | @close="drawerClose" |
| | | > |
| | | <template #title> |
| | | <pageHeadLeft :checked="true"></pageHeadLeft> |
| | | <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"> |
| | | 共<span class="m-1">222</span>封 <LeftOutlined style="padding: 0 20px" /><RightOutlined /> |
| | | 共<span class="m-1">{{ props.allList.length }}</span |
| | | >封 |
| | | <LeftOutlined style="padding: 0 20px" @click="fnPrev" /> |
| | | <RightOutlined @click="fnNext" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <div class="flex-between"> |
| | | <template #footer> |
| | | <div style="display: flex"> |
| | | <a-textarea autoSize size="large" v-model:value="content" placeholder="快速回复"> |
| | | <template #prefix> |
| | | <RollbackOutlined style="color: #999" /> |
| | | </template> |
| | | </a-textarea> |
| | | <a-button size="large" type="primary" style="margin-left: 10px" @click="fnQuickReply" |
| | | >发送 |
| | | </a-button> |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <div class="flex-between"> |
| | | <div class="ct-left p-2" :class="isOpen ? 'isOpen' : 'onOpen'"> |
| | | <div class="title" style="margin-bottom: 20px;"> |
| | | <div class="left"> |
| | | <span style="margin-right: 20px; font-size: 24px; font-weight: 700">标题</span> |
| | | <span style="margin-right: 10px; font-size: 16px"><PushpinOutlined /></span> |
| | | </div> |
| | | <div class="right"> |
| | | <div class="tate"> 2024-06-08 15:03:09 </div> |
| | | <div> |
| | | <a-dropdown-button> |
| | | <span><LeftOutlined /></span> |
| | | <a-divider type="vertical" /> |
| | | <span><DoubleLeftOutlined /></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 class="user p-1"> |
| | | <div style="display: flex;align-items: center;"> |
| | | <a-avatar size="small" style="margin-right: 8px" src="#" /> xxx <span>{{`<dddddddddd@qq.com>`}}</span> |
| | | <span style="margin: 0 10px;">发送</span> |
| | | <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">ssss</span> |
| | | <CopyOutlined /> |
| | | </div> |
| | | <div class="display-flex p-2"> |
| | | <a-button type="link" size="small">往来邮件</a-button></div |
| | | > |
| | | <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="#" /> xxx <span>{{`<dddddddddd@qq.com>`}}</span> |
| | | <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>{{`<dddddddddd@qq.com>`}}</span><span>暂未查询到该客户的当地时间</span><span>2024-06-08 22:22</span> |
| | | </div> |
| | | <div class="ct"> |
| | | <Tinymce></Tinymce> |
| | | </div> |
| | | <a-input size="large" v-model:value="userName" placeholder="快速回复"> |
| | | <template #prefix> |
| | | <LeftOutlined style="color: #999;"/> |
| | | </template> |
| | | </a-input> |
| | | <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 v-show="isOpen" class="ct-right p-2">sssss</div> |
| | | </div> |
| | | </div> |
| | | |
| | | |
| | | <div @click="fuToggleContent" class="toggle-btn" :class="isOpen ? 'onIconOpen' : 'iconOpen'"> |
| | | <LeftOutlined v-if="!isOpen" /> |
| | | <RightOutlined v-else /> |
| | | <LeftOutlined v-if="!isOpen" /> |
| | | <RightOutlined v-else /> |
| | | </div> |
| | | </div> |
| | | </a-drawer> |
| | | </template> |
| | | |
| | | <script lang="ts" setup>; |
| | | <script lang="ts" setup> |
| | | name: 'drawerDetail'; |
| | | import { ref, watch, defineProps, defineEmits, computed, reactive } from 'vue'; |
| | | |
| | | import { ref, watch, defineProps, defineEmits, computed } from 'vue'; |
| | | import { |
| | | LeftOutlined, |
| | | RightOutlined, |
| | | DoubleLeftOutlined, |
| | | PushpinOutlined, |
| | | CopyOutlined, |
| | | UserOutlined |
| | | PushpinOutlined, |
| | | CopyOutlined, |
| | | UserOutlined, |
| | | RollbackOutlined, |
| | | } from '@ant-design/icons-vue'; |
| | | import pageHeadLeft from '../pageHeadLeft.vue'; |
| | | import Tinymce from '@/components/Tinymce/src/index.vue'; |
| | | import pageHeadLeft from './pageHeadLeft.vue'; |
| | | import { TinymcePw } from '@/components/Tinymce'; |
| | | import { getMailInfoApi, setQuickReplyAPi } from '@/api/email/userList'; |
| | | import { useCollapseStore } from '@/store/modules/useCollapseStore'; |
| | | import { nextTick } from 'vue'; |
| | | import { formatToDateDay } from '@/utils/dateUtil'; |
| | | import { useLoading } from '@/components/Loading'; |
| | | |
| | | // const [open, close, setTip] = useLoading(); |
| | | // 定义属性 |
| | | interface Props { |
| | | modelValue: boolean; |
| | |
| | | placement?: 'left' | 'right' | 'top' | 'bottom'; |
| | | idName?: string; |
| | | selectIds?: number[]; |
| | | mailId?: string; |
| | | selectAllRow: Array<any>; |
| | | allList; |
| | | } |
| | | |
| | | const props = defineProps<Props>(); |
| | | |
| | | // 定义事件 |
| | | const tableRowData = ref<Record<string, any>>({}); |
| | | const emit = defineEmits(['update:modelValue', 'updateData']); |
| | | |
| | | // 内部状态 |
| | | const drawerOpen = ref(props.modelValue); |
| | | |
| | | const TinymcePwRef = ref(); |
| | | const docCode = ref(props.mailId); |
| | | watch( |
| | | () => props.mailId, |
| | | (newVal) => { |
| | | docCode.value = newVal; |
| | | }, |
| | | ); |
| | | // 监听属性变化 |
| | | watch( |
| | | () => props.modelValue, |
| | | (newValue) => { |
| | | drawerOpen.value = newValue; |
| | | if (props.selectIds && props.selectIds.length > 0) { |
| | | } else { |
| | | nextTick(() => { |
| | | console.log(newValue, '---------4', TinymcePwRef.value); |
| | | }); |
| | | if (newValue) { |
| | | fnGetMailInfo(props.mailId); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | function fnGetMailInfo(id) { |
| | | getMailInfoApi({ docCode: id }) |
| | | .then((res) => { |
| | | docCode.value = id; |
| | | tableRowData.value = res.data; |
| | | }) |
| | | .catch(() => {}); |
| | | } |
| | | // 更新外部属性 |
| | | watch(drawerOpen, (newValue) => { |
| | | emit('update:modelValue', newValue); |
| | | }); |
| | | import { getUserListApi } from '@/api/email/userList'; |
| | | |
| | | // 方法 |
| | | |
| | | import { useCollapseStore } from '@/store/modules/useCollapseStore'; |
| | | const collapseStore = useCollapseStore(); |
| | | const afterOpenChange = (bool: boolean) => { |
| | | if (bool) { |
| | | fnGetUserList({ page: 1, pageSize: 30 }); |
| | | } |
| | | |
| | | collapseStore.toggle(false); |
| | | |
| | | |
| | | collapseStore.toggle(false); |
| | | }; |
| | | const close = (e) => { |
| | | const drawerClose = (e) => { |
| | | drawerOpen.value = false; |
| | | }; |
| | | const fnGetUserList = (params) => { |
| | | // getUserListApi(params).then((res) => { |
| | | // if (res && res.items && Array.isArray(res.items)) { |
| | | // dataSource.value = res.items; |
| | | // selectContactNum.value = res.total; |
| | | // } else { |
| | | // console.error('Invalid response format:', res); |
| | | // } |
| | | // }); |
| | | |
| | | function truncateString(str, maxLength) { |
| | | return str.length > maxLength ? str.substring(0, maxLength) + '...' : str; |
| | | } |
| | | // 计算属性 |
| | | const title = computed(() => props.title || 'Basic Drawer'); |
| | | const placement = computed(() => props.placement || 'right'); |
| | | const idName = computed(() => props.idName || 'recipients'); |
| | | |
| | | // // 显示抽屉的方法 |
| | | // const showDrawer = () => { |
| | | // drawerOpen.value = true; |
| | | // }; |
| | | |
| | | const fnSaveOpenChange = () => { |
| | | // console.log('selectedRowKeys changed: ', state.selectedRowKeys); |
| | | // drawerOpen.value = false; |
| | | // emit('update:modelValue', false); |
| | | // const data = { |
| | | // selectedRowKeys: state.selectedRowKeys, |
| | | //; idName: idName.value, |
| | | // }; |
| | | // emit('updateData', data); |
| | | const fnGetUserList = (params) => { |
| | | // 调用接口逻辑 |
| | | }; |
| | | |
| | | const userName = ref(''); |
| | | const isOpen = ref(false) |
| | | function fuToggleContent (){ |
| | | isOpen.value = !isOpen.value |
| | | // 计算属性 |
| | | const placement = computed(() => props.placement || 'right'); |
| | | |
| | | // 抽屉开关 |
| | | const fnSaveOpenChange = () => { |
| | | // 抽屉保存逻辑 |
| | | }; |
| | | |
| | | const content = ref(''); |
| | | const isOpen = ref(false); |
| | | |
| | | function fuToggleContent() { |
| | | isOpen.value = !isOpen.value; |
| | | } |
| | | |
| | | function fnPrev() { |
| | | const id = getPrevId(props.allList, docCode.value); |
| | | fnGetMailInfo(id); |
| | | } |
| | | function fnNext() { |
| | | const id = getNextId(props.allList, docCode.value); |
| | | fnGetMailInfo(id); |
| | | } |
| | | function getNextId(list, id) { |
| | | const index = list.findIndex((item) => item.docCode === id); |
| | | if (index < list.length - 1) { |
| | | return list[index + 1].docCode; |
| | | } else { |
| | | return list[0].docCode; |
| | | } |
| | | } |
| | | function getPrevId(list, id) { |
| | | const index = list.findIndex((item) => item.docCode === id); |
| | | if (index > 0) { |
| | | return list[index - 1].docCode; |
| | | } else { |
| | | return list[list.length - 1].docCode; |
| | | } |
| | | } |
| | | |
| | | import { useMessage } from '@/hooks/web/useMessage'; |
| | | |
| | | const { createMessage } = useMessage(); |
| | | function fnQuickReply() { |
| | | if (!content.value) { |
| | | createMessage.warning('请输入回复内容'); |
| | | return; |
| | | } |
| | | const data = { |
| | | docCode: docCode.value, |
| | | content: content.value, |
| | | }; |
| | | setQuickReplyAPi(data).then((res) => { |
| | | if (res.code == 0) { |
| | | createMessage.success(res.msg); |
| | | |
| | | fnGetMailInfo(props.mailId); |
| | | } |
| | | }); |
| | | } |
| | | import { useRouter } from 'vue-router'; |
| | | const router = useRouter(); |
| | | function replyEmail(row) { |
| | | router.push({ path: '/email/edit', query: { docCode: row.docCode, type: 'reply' } }); |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | /* 样式可以在这里定义 */ |
| | | |
| | | .table-content { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | border-top: 1px solid #f0f0f0; |
| | | |
| | | .left { |
| | | width: 50%; |
| | | width: 80%; |
| | | height: 100%; |
| | | border-right: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | .right { |
| | | width: 50%; |
| | | height: 100%; |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | .ct{ |
| | | // height: 66vh;height |
| | | .ct { |
| | | margin: 20px 0; |
| | | } |
| | | |
| | | .flex-between{ |
| | | .flex-between { |
| | | display: flex; |
| | | padding-top: 4%; |
| | | } |
| | | |
| | | .ct-left{ |
| | | padding-right: 20px; |
| | | // border-right: 1px solid #f0f0f0; |
| | | } |
| | | .ct-left { |
| | | padding-right: 20px; |
| | | } |
| | | |
| | | .ct-right{ |
| | | border-left: 1px solid #f0f0f0; |
| | | |
| | | } |
| | | .ct-right { |
| | | border-left: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | .toggle-btn { |
| | | display: flex; |
| | | position: absolute; |
| | | z-index: 99; |
| | | top: 50%; |
| | | width: 20px; /* 原始宽度 */ |
| | | width: 20px; |
| | | height: 54px; |
| | | padding-left: 5px; |
| | | transform: translateY(-50%); |
| | | border: 1px solid #f0f0f0; |
| | | border-right: none; |
| | | border-radius: 10px 0 0 10px; |
| | | border-radius: 10px 0 0 10px; |
| | | background: #fafafa; |
| | | |
| | | } |
| | | |
| | | .onOpen { |
| | |
| | | |
| | | .iconOpen { |
| | | right: 0%; |
| | | |
| | | } |
| | | |
| | | .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> |