307 lines
7.0 KiB
Vue
307 lines
7.0 KiB
Vue
<!-- 页面:消息详情(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">></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>
|