fjrcloud-community-app/pages/sub/notice/detail.vue

365 lines
8.0 KiB
Vue
Raw Normal View History

2026-04-22 20:57:53 +08:00
<!-- 通知公告详情页 -->
<template>
2026-04-25 22:10:33 +08:00
<s-layout title="通知公告" color="#333333">
<view class="detail-page">
<!-- 渐变背景 -->
<view class="gradient-bg"></view>
2026-04-22 20:57:53 +08:00
<!-- 头部区域 -->
<view class="detail-header">
<view class="header-inner">
<!-- 文章标题 -->
<view class="article-title">
<text class="title-text">{{ noticeInfo.title }}</text>
2026-04-22 20:57:53 +08:00
</view>
<!-- 发布信息 -->
<view class="publish-info">
<view class="publisher">
<image class="publisher-avatar" src="/static/img/person.png" mode="aspectFill" />
<text class="publisher-name">{{ noticeInfo.publisher }}</text>
</view>
<text class="publish-date">{{ noticeInfo.publishDate ? sheep.$helper.timeFormat(noticeInfo.publishDate, 'yyyy/mm/dd hh:MM:ss') : '' }}</text>
</view>
2026-04-22 20:57:53 +08:00
<!-- 分割线 -->
<view class="divider"></view>
2026-04-22 20:57:53 +08:00
</view>
</view>
<!-- 富文本内容 - 滚动区域 -->
<scroll-view class="article-scroll" scroll-y>
<view class="article-content">
<view class="article-inner">
<mp-html :content="noticeInfo.content"></mp-html>
</view>
</view>
<!-- 占位防止内容被底部附件遮挡 -->
<view class="bottom-placeholder" v-if="noticeInfo.attachmentList && noticeInfo.attachmentList.length > 0"></view>
</scroll-view>
<!-- 附件列表 -->
<view class="attachment-section" v-if="noticeInfo.attachmentList && noticeInfo.attachmentList.length > 0">
<view class="attachment-inner">
<view
class="attachment-item"
v-for="(item, index) in noticeInfo.attachmentList"
:key="index"
@tap="downloadAttachment(item)"
>
<view class="attachment-left">
<image class="attachment-icon" :src="getAttachmentIcon(item.type)" mode="aspectFit" />
<text class="attachment-name">{{ item.name }}</text>
</view>
<image class="download-icon" src="/static/img/right-icon.png" mode="aspectFit" />
</view>
2026-04-22 20:57:53 +08:00
</view>
</view>
</view>
</s-layout>
</template>
<script setup>
import { ref } from 'vue';
2026-04-22 20:57:53 +08:00
import { onLoad } from '@dcloudio/uni-app';
import NoticeApi from '@/sheep/api/community/notice';
2026-04-22 20:57:53 +08:00
import sheep from '@/sheep';
// 公告信息
const noticeInfo = ref({
title: '',
publisher: '',
publishDate: '',
content: '',
attachmentList: []
2026-04-22 20:57:53 +08:00
});
// 页面加载
onLoad((options) => {
if (options.id) {
loadNoticeDetail(options.id);
}
});
// 加载公告详情
async function loadNoticeDetail(id) {
const { code, data } = await NoticeApi.getDetail(id);
if (code === 0 && data) {
noticeInfo.value = {
title: data.title || '',
publisher: data.publisher || '',
publishDate: data.publishTime || '',
content: data.content || '',
attachmentList: (data.attachmentList || []).map((item) => ({
name: item.name,
url: item.url,
type: getFileType(item.name),
})),
};
}
}
// 根据文件名判断文件类型
function getFileType(fileName) {
if (!fileName) return 'file';
const ext = fileName.split('.').pop().toLowerCase();
const typeMap = {
png: 'image',
jpg: 'image',
jpeg: 'image',
gif: 'image',
xls: 'excel',
xlsx: 'excel',
pdf: 'pdf',
doc: 'word',
docx: 'word',
2026-04-22 20:57:53 +08:00
};
return typeMap[ext] || 'file';
2026-04-22 20:57:53 +08:00
}
// 获取附件图标
function getAttachmentIcon(type) {
const iconMap = {
image: '/static/img/eli-icon1.png',
excel: '/static/img/eli-icon2.png',
pdf: '/static/img/eli-icon2.png',
word: '/static/img/eli-icon2.png'
};
return iconMap[type] || '/static/img/eli-icon2.png';
}
// 下载附件
function downloadAttachment(item) {
if (!item.url) {
uni.showToast({
title: '附件链接不存在',
icon: 'none'
});
return;
}
uni.showLoading({
title: '下载中...'
});
uni.downloadFile({
url: item.url,
success: (res) => {
if (res.statusCode === 200) {
// 保存到本地
uni.saveFile({
tempFilePath: res.tempFilePath,
success: (saveRes) => {
uni.hideLoading();
uni.showToast({
title: '下载成功',
icon: 'success'
});
// 打开文件
uni.openDocument({
filePath: saveRes.savedFilePath,
showMenu: true,
success: () => {
console.log('打开文档成功');
},
fail: () => {
uni.showToast({
title: '无法打开该文件',
icon: 'none'
});
}
});
},
fail: () => {
uni.hideLoading();
uni.showToast({
title: '保存失败',
icon: 'none'
});
}
});
} else {
uni.hideLoading();
uni.showToast({
title: '下载失败',
icon: 'none'
});
}
},
fail: () => {
uni.hideLoading();
uni.showToast({
title: '下载失败',
icon: 'none'
});
}
});
}
</script>
<style lang="scss" scoped>
/* 页面容器:纵向 flex 布局,减去导航栏高度 */
2026-04-25 22:10:33 +08:00
.detail-page {
position: relative;
display: flex;
flex-direction: column;
height: calc(100vh - 176rpx);
overflow: hidden;
2026-04-25 22:10:33 +08:00
}
/* 渐变背景 */
.gradient-bg {
2026-04-25 22:10:33 +08:00
position: absolute;
top: 0;
left: 0;
width: 750rpx;
height: 660rpx;
background: linear-gradient(180deg, #F8EDE8 0%, #F5F5F5 50%);
z-index: 0;
pointer-events: none;
}
/* 头部区域:正常文档流 */
2026-04-22 20:57:53 +08:00
.detail-header {
position: relative;
z-index: 10;
flex-shrink: 0;
}
.header-inner {
padding: 0 32rpx;
2026-04-22 20:57:53 +08:00
}
/* 底部占位 - 基础间距 + 安全区域 */
2026-04-22 20:57:53 +08:00
.bottom-placeholder {
height: calc(40rpx + env(safe-area-inset-bottom));
2026-04-22 20:57:53 +08:00
}
/* 文章标题 */
.article-title {
padding: 32rpx 0 24rpx;
.title-text {
font-size: 36rpx;
font-weight: 600;
color: #333333;
line-height: 1.5;
}
}
/* 发布信息 */
.publish-info {
display: flex;
align-items: center;
justify-content: space-between;
padding-bottom: 24rpx;
.publisher {
display: flex;
align-items: center;
.publisher-avatar {
width: 48rpx;
height: 48rpx;
margin-right: 16rpx;
}
.publisher-name {
font-size: 28rpx;
color: #666666;
}
}
.publish-date {
font-size: 26rpx;
color: #999999;
}
}
/* 分割线 */
.divider {
height: 1rpx;
background-color: #E5E5E5;
margin-bottom: 32rpx;
}
/* 富文本滚动区域flex:1 占满剩余空间height:0 是小程序 scroll-view 配合 flex 的关键 */
2026-04-22 20:57:53 +08:00
.article-scroll {
position: relative;
z-index: 5;
flex: 1;
height: 0;
2026-04-22 20:57:53 +08:00
}
/* 富文本内容 - 圆角背景卡片 */
2026-04-22 20:57:53 +08:00
.article-content {
margin: 0 32rpx;
2026-04-22 20:57:53 +08:00
border-radius: 24rpx;
}
/* 富文本内容内层 */
.article-inner {
2026-04-22 20:57:53 +08:00
:deep(p) {
font-size: 28rpx;
color: #333333;
line-height: 1.8;
margin-bottom: 16rpx;
}
:deep(img) {
width: 100%;
border-radius: 16rpx;
margin: 24rpx 0;
}
}
/* 附件区域 */
2026-04-22 20:57:53 +08:00
.attachment-section {
flex-shrink: 0;
max-height: 360rpx;
2026-04-22 20:57:53 +08:00
background: #FFFFFF;
box-shadow: 0rpx -8rpx 64rpx 0rpx rgba(0, 0, 0, 0.16);
border-radius: 24rpx 24rpx 0 0;
2026-04-22 20:57:53 +08:00
overflow-y: auto;
z-index: 9999;
}
.attachment-inner {
padding: 24rpx 32rpx;
2026-04-22 20:57:53 +08:00
}
.attachment-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 0;
&:not(:last-child) {
border-bottom: 1rpx solid #F0F0F0;
}
.attachment-left {
display: flex;
align-items: center;
flex: 1;
.attachment-icon {
width: 48rpx;
height: 48rpx;
margin-right: 20rpx;
}
.attachment-name {
font-size: 28rpx;
color: #333333;
}
}
.download-icon {
width: 32rpx;
height: 32rpx;
}
}
</style>