Files
cz-web/src/views/message/detail.vue
2026-10-13 16:08:55 +08:00

307 lines
7.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 页面:消息详情(MessageDetail) -->
<script setup lang="ts">
import { computed, onMounted, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { useRoute, useRouter } from 'vue-router'
import { PageHead } from '@/components'
import { useMessageStore } from '@/stores/modules/message'
import { formatFileSize } from '@/utils/format'
const route = useRoute()
const router = useRouter()
const messageStore = useMessageStore()
const item = computed(() => messageStore.current)
const messageId = computed(() => String(route.params.id))
function load(): void {
void messageStore.fetchDetail(messageId.value)
}
function onBack(): void {
void router.push('/message')
}
function onPreview(): void {
ElMessage.info('附件待接口接入')
}
function onDownload(): void {
ElMessage.info('附件待接口接入')
}
watch(messageId, load)
onMounted(load)
</script>
<template>
<div class="message-detail">
<PageHead
title="消息详情"
slogan="查看站内消息完整内容与附件资料"
/>
<div class="container message-detail__wrap">
<nav class="message-detail__breadcrumb">
<RouterLink to="/message" class="message-detail__breadcrumb-link">
消息中心
</RouterLink>
<span class="message-detail__breadcrumb-sep">&gt;</span>
<span class="message-detail__breadcrumb-current">{{ item ? `${item.type}详情` : '消息详情' }}</span>
</nav>
<template v-if="item">
<article class="message-detail__card">
<header class="message-detail__head">
<h1 class="message-detail__title">
{{ item.title }}
</h1>
<p class="message-detail__time">
发布时间:{{ item.publishTime }}
</p>
</header>
<div class="message-detail__content">
{{ item.content }}
</div>
<section v-if="item.attachments.length > 0" class="message-detail__attachments">
<h2 class="message-detail__attachments-title">
附件({{ item.attachments.length }})
</h2>
<ul class="message-detail__file-list">
<li
v-for="(file, index) in item.attachments"
:key="`${file.name}-${index}`"
class="message-detail__file"
>
<div class="message-detail__file-info">
<span class="message-detail__file-name" :title="file.name">{{ file.name }}</span>
<span class="message-detail__file-meta">
{{ formatFileSize(file.size) }} · 上传于{{ file.uploadTime }}
</span>
</div>
<div class="message-detail__file-actions">
<button
type="button"
class="message-detail__file-btn"
@click="onPreview"
>
预览
</button>
<button
type="button"
class="message-detail__file-btn"
@click="onDownload"
>
下载
</button>
</div>
</li>
</ul>
</section>
<div class="message-detail__actions">
<button
type="button"
class="message-detail__back"
@click="onBack"
>
返回
</button>
</div>
</article>
</template>
<p v-else class="message-detail__empty">
消息不存在
</p>
</div>
</div>
</template>
<style lang="less" scoped>
.message-detail {
.flex(column, flex-start, stretch);
gap: 0;
width: 100%;
min-height: 100%;
padding-bottom: @spacing-page-bottom;
background: @bg-color;
&__wrap {
padding-top: @spacing-lg;
padding-right: @home-gutter;
padding-left: @home-gutter;
box-sizing: border-box;
@media (max-width: 1600px) {
padding-right: @spacing-lg;
padding-left: @spacing-lg;
}
}
&__breadcrumb {
.flex(row, flex-start, center);
gap: @spacing-xs;
margin-bottom: @spacing-base;
font-size: @font-size-sm;
line-height: 1.5;
color: @text-color-secondary;
}
&__breadcrumb-link {
color: @text-color-secondary;
&:hover {
color: @primary-strong;
}
}
&__breadcrumb-current {
color: @heading-color;
font-weight: 500;
}
&__card {
padding: @spacing-xl;
border: 1px solid @border-color;
border-radius: @radius-base;
background: @white;
box-sizing: border-box;
}
&__head {
padding-bottom: @spacing-base;
border-bottom: 1px solid @border-color;
}
&__title {
margin: 0;
font-size: @font-size-xl;
font-weight: 600;
line-height: 1.4;
color: @heading-color;
}
&__time {
margin: @spacing-sm 0 0;
font-size: @font-size-sm;
line-height: 1.4;
color: @text-color-secondary;
}
&__content {
margin-top: @spacing-lg;
color: @text-color;
font-size: @font-size-base;
line-height: 1.8;
text-align: left;
white-space: pre-wrap;
word-break: break-word;
}
&__attachments {
margin-top: @spacing-xl;
}
&__attachments-title {
margin: 0 0 @spacing-base;
font-size: @font-size-sm;
font-weight: 600;
color: @heading-color;
}
&__file-list {
.flex(column, flex-start, stretch);
gap: @spacing-sm;
margin: 0;
padding: 0;
}
&__file {
.flex(row, space-between, center);
gap: @spacing-base;
width: 100%;
max-width: 520px;
padding: @spacing-base;
border: 1px solid @border-color;
border-radius: @radius-base;
background: @bg-color-light;
list-style: none;
box-sizing: border-box;
}
&__file-info {
.flex(column, flex-start, flex-start);
gap: @spacing-xs;
min-width: 0;
}
&__file-name {
font-size: @font-size-sm;
font-weight: 600;
color: @heading-color;
.ellipsis();
}
&__file-meta {
font-size: @font-size-xs;
color: @text-color-secondary;
.ellipsis();
}
&__file-actions {
.flex(row, flex-end, center);
gap: @spacing-sm;
flex-shrink: 0;
}
&__file-btn {
height: 28px;
padding: 0 @spacing-sm;
border: none;
border-radius: @radius-round;
background: transparent;
color: @primary-strong;
font-size: @font-size-sm;
cursor: pointer;
&:hover {
background: fade(@primary-strong, 8%);
}
}
&__actions {
.flex(row, flex-end);
margin-top: @spacing-xl;
}
&__back {
min-width: 88px;
height: 36px;
padding: 0 @spacing-lg;
border: none;
border-radius: @radius-round;
background: @primary-strong;
color: @white;
font-size: @font-size-sm;
font-weight: 500;
cursor: pointer;
transition: background 0.2s;
&:hover {
background: @primary-hover;
}
}
&__empty {
padding: @spacing-xxl 0;
text-align: center;
font-size: @font-size-sm;
color: @text-color-secondary;
}
}
</style>