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

365 lines
8.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!-- 通知公告详情页 -->
<template>
<s-layout title="通知公告" color="#333333">
<view class="detail-page">
<!-- 渐变背景 -->
<view class="gradient-bg"></view>
<!-- 头部区域 -->
<view class="detail-header">
<view class="header-inner">
<!-- 文章标题 -->
<view class="article-title">
<text class="title-text">{{ noticeInfo.title }}</text>
</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>
<!-- 分割线 -->
<view class="divider"></view>
</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>
</view>
</view>
</view>
</s-layout>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import NoticeApi from '@/sheep/api/community/notice';
import sheep from '@/sheep';
// 公告信息
const noticeInfo = ref({
title: '',
publisher: '',
publishDate: '',
content: '',
attachmentList: []
});
// 页面加载
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',
};
return typeMap[ext] || 'file';
}
// 获取附件图标
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 布局,减去导航栏高度 */
.detail-page {
position: relative;
display: flex;
flex-direction: column;
height: calc(100vh - 176rpx);
overflow: hidden;
}
/* 渐变背景 */
.gradient-bg {
position: absolute;
top: 0;
left: 0;
width: 750rpx;
height: 660rpx;
background: linear-gradient(180deg, #F8EDE8 0%, #F5F5F5 50%);
z-index: 0;
pointer-events: none;
}
/* 头部区域:正常文档流 */
.detail-header {
position: relative;
z-index: 10;
flex-shrink: 0;
}
.header-inner {
padding: 0 32rpx;
}
/* 底部占位 - 基础间距 + 安全区域 */
.bottom-placeholder {
height: calc(40rpx + env(safe-area-inset-bottom));
}
/* 文章标题 */
.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 的关键 */
.article-scroll {
position: relative;
z-index: 5;
flex: 1;
height: 0;
}
/* 富文本内容 - 圆角背景卡片 */
.article-content {
margin: 0 32rpx;
border-radius: 24rpx;
}
/* 富文本内容内层 */
.article-inner {
:deep(p) {
font-size: 28rpx;
color: #333333;
line-height: 1.8;
margin-bottom: 16rpx;
}
:deep(img) {
width: 100%;
border-radius: 16rpx;
margin: 24rpx 0;
}
}
/* 附件区域 */
.attachment-section {
flex-shrink: 0;
max-height: 360rpx;
background: #FFFFFF;
box-shadow: 0rpx -8rpx 64rpx 0rpx rgba(0, 0, 0, 0.16);
border-radius: 24rpx 24rpx 0 0;
overflow-y: auto;
z-index: 9999;
}
.attachment-inner {
padding: 24rpx 32rpx;
}
.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>