feat 搭建架构骨架

This commit is contained in:
Ironsp
2026-09-24 09:09:47 +08:00
parent dd9f6b77a4
commit 7a2efa3fea
180 changed files with 18967 additions and 9 deletions

View File

@@ -0,0 +1,211 @@
<script setup lang="ts">
import { computed, onMounted, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { useRoute, useRouter } from 'vue-router'
import { AppButton } from '@/components'
// 页面容器:数据只经 store,不直接 import api
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">
<nav class="message-detail__breadcrumb text-secondary">
<RouterLink to="/message" class="link">
消息中心
</RouterLink>
<span> &gt; </span>
<span>{{ item ? `${item.type}详情` : '消息详情' }}</span>
</nav>
<template v-if="item">
<article class="message-detail__card">
<h1 class="message-detail__title">
{{ item.title }}
</h1>
<p class="message-detail__time text-secondary">
发布时间:{{ item.publishTime }}
</p>
<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 text-secondary">
{{ formatFileSize(file.size) }} · 上传于{{ file.uploadTime }}
</span>
</div>
<div class="message-detail__file-actions">
<button class="message-detail__file-btn" @click="onPreview">
预览
</button>
<button class="message-detail__file-btn" @click="onDownload">
下载
</button>
</div>
</li>
</ul>
</section>
<div class="message-detail__actions">
<AppButton type="primary" @click="onBack">
返回
</AppButton>
</div>
</article>
</template>
<p v-else class="message-detail__empty text-secondary">
消息不存在
</p>
</div>
</template>
<style lang="less" scoped>
.message-detail {
padding-top: @spacing-lg;
padding-bottom: @spacing-xxl;
&__breadcrumb {
margin-bottom: @spacing-base;
font-size: @font-size-base;
}
&__card {
padding: @spacing-xl;
border-radius: @radius-lg;
background: @white;
box-shadow: @shadow-base;
}
&__title {
font-size: @font-size-xl;
font-weight: 600;
color: @heading-color;
}
&__time {
margin-top: @spacing-sm;
font-size: @font-size-sm;
}
&__content {
margin-top: @spacing-lg;
padding: @spacing-base;
border-radius: @radius-base;
background: @bg-color-light;
color: @text-color;
font-size: @font-size-base;
line-height: 1.8;
white-space: pre-wrap;
word-break: break-word;
}
&__attachments {
margin-top: @spacing-lg;
&-title {
margin-bottom: @spacing-sm;
font-size: @font-size-lg;
font-weight: 600;
color: @heading-color;
}
}
&__file-list {
.flex(column, flex-start);
gap: @spacing-sm;
}
&__file {
.flex(row, space-between);
gap: @spacing-base;
padding: @spacing-sm @spacing-base;
border: 1px solid @border-color;
border-radius: @radius-base;
background: @bg-color-light;
list-style: none;
}
&__file-info {
.flex(column, flex-start);
gap: 2px;
min-width: 0;
}
&__file-name {
font-size: @font-size-base;
color: @heading-color;
.ellipsis();
}
&__file-meta {
font-size: @font-size-sm;
}
&__file-actions {
.flex(row, center);
gap: @spacing-sm;
flex-shrink: 0;
}
&__file-btn {
font-size: @font-size-sm;
color: @primary-color;
transition: opacity 0.2s;
&:hover {
opacity: 0.75;
}
}
&__actions {
.flex(row, flex-start);
margin-top: @spacing-lg;
}
&__empty {
padding: @spacing-xxl 0;
text-align: center;
font-size: @font-size-base;
}
}
</style>