diff --git a/frontend/src/components/mail/ConversationMessagePanel.vue b/frontend/src/components/mail/ConversationMessagePanel.vue index 35c1cf0..3fce3e9 100644 --- a/frontend/src/components/mail/ConversationMessagePanel.vue +++ b/frontend/src/components/mail/ConversationMessagePanel.vue @@ -2,7 +2,8 @@ // "같은 대화" 칸에서 펼친 줄의 안 (14단계 — 디자인 원본 Thread14 "하나 펼침") // 받는 사람 · 제목 한 줄씩, 본문(MailBodyFrame — 검색 쿼리 없이 받은 본문이라 강조가 없다), [답장] · [이 메일만 열기](36 — 밀도 예외 --size-notice-action 재사용). // - 본문이 다 보이지 않으면(서버의 isHtmlBodyOmitted · isBodyTruncated) 읽기 화면과 같은 안내 줄(MAIL_BODY_NOTICES)을 본문 위에 — 읽기 화면도 같은 본문이다. -// 외부 이미지 안내 · 첨부 목록은 두지 않는다 — [이 메일만 열기]로 연 읽기 화면에 있다 +// 외부 이미지 안내 · 첨부 목록은 두지 않는다 — [이 메일만 열기]로 연 읽기 화면에 있다. 첨부가 있으면 본문 아래 · [답장] 위에 +// "첨부 파일 N개는 [이 메일만 열기]를 누르면 볼 수 있습니다." (수는 읽기 화면의 "첨부 파일 N개"와 같다 — 본문 그림 빼고 · 대용량 첨부 더해) // - 본문을 받는 동안은 뼈대(aria-busy), 못 받으면 사전 문구 + [다시 시도]. 그사이 지워진 메일(RES_001)이면 [다시 시도] · [답장] · [이 메일만 열기] 없이 — // 스토어가 대화를 다시 받아 이 줄을 뺀다. 화면 낭독용 상태 영역은 늘 두고 글만 바꾼다 // - [답장]은 읽기 화면의 [답장]과 같은 쓰기 화면이고, 임시 저장본 · 예약한 메일에는 없다. [이 메일만 열기]는 그 메일을 읽기 화면으로 연다(mail-conversation.ts) — @@ -15,7 +16,9 @@ import MailBodyFrame from '@/components/mail/MailBodyFrame.vue' import { useMailPrint } from '@/composables/useMailPrint' import { MAIL_NO_SUBJECT } from '@/shared/constants/mail' import { MAIL_CONVERSATION_TEXT } from '@/shared/constants/mail-conversation' +import { formatCount } from '@/shared/utils/format' import { formatAddressList } from '@/shared/utils/mail-address' +import { listedAttachments } from '@/shared/utils/mail-attachment' import { mailBodyNotices } from '@/shared/utils/mail-body-notices' import type { ConversationRow } from '@/shared/utils/mail-conversation' import type { ConversationDetailState } from '@/stores/mail.store' @@ -47,6 +50,10 @@ const failure = computed(() => (props.detail?.status === 'error' ? props.detail. /** 그사이 지워진 메일 — 다시 해도 같고 그 메일로 갈 곳도 없다 */ const missing = computed(() => failure.value?.code === 'RES_001') const bodyNotices = computed(() => (ready.value ? mailBodyNotices(ready.value) : [])) +/** 읽기 화면에서 볼 수 있는 첨부 수 — 본문 그림(isInline)은 빼고 대용량 첨부는 더한다 (MessageReader 의 첨부 칸과 같은 수) */ +const attachmentCount = computed(() => + ready.value ? listedAttachments(ready.value.attachments).length + (ready.value.largeFiles?.length ?? 0) : 0, +) const bodyTitle = computed(() => MAIL_CONVERSATION_TEXT.bodyTitle(props.row.sender.name, props.row.time)) /** 본문 안에서 누른 키 — Ctrl+P(맥 ⌘P)면 브라우저 인쇄 대신 이 메일의 인쇄 화면 */ @@ -97,6 +104,18 @@ function onFrameKeydown(event: KeyboardEvent) { :title="bodyTitle" @frame-keydown="onFrameKeydown" /> +
(), {
+const props = withDefaults(defineProps