|
|
|
|
|
<template>
|
|
|
|
|
|
<view class="notice-detail-page">
|
|
|
|
|
|
<view class="content" v-if="!loading">
|
|
|
|
|
|
<view class="detail-card" v-if="notice && (notice.noticeTitle || notice.noticeId)">
|
|
|
|
|
|
<view class="title-section">
|
|
|
|
|
|
<text class="detail-title">{{ notice.noticeTitle || '未命名通知' }}</text>
|
|
|
|
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="info-list">
|
|
|
|
|
|
<view class="row" v-if="notice.noticeType">
|
|
|
|
|
|
<text class="label">通知类型:</text>
|
|
|
|
|
|
<text class="value">{{ notice.noticeType }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="row" v-if="notice.draftDeptName">
|
|
|
|
|
|
<text class="label">通知单位:</text>
|
|
|
|
|
|
<text class="value">{{ notice.draftDeptName }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="row" v-if="notice.noticeScope">
|
|
|
|
|
|
<text class="label">通知范围:</text>
|
|
|
|
|
|
<text class="value">{{ notice.noticeScope }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="row" v-if="notice.noticeTime">
|
|
|
|
|
|
<text class="label">通知时间:</text>
|
|
|
|
|
|
<text class="value">{{ notice.noticeTime }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="content-box">
|
|
|
|
|
|
<jyf-parser
|
|
|
|
|
|
v-if="notice.noticeContent"
|
|
|
|
|
|
:html="notice.noticeContent"
|
|
|
|
|
|
ref="article"
|
|
|
|
|
|
:tag-style="tagStyle"
|
|
|
|
|
|
></jyf-parser>
|
|
|
|
|
|
<view class="empty" v-else>暂无通知内容</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="attach-box" v-if="fileList.length">
|
|
|
|
|
|
<view class="attach-title">附件列表</view>
|
|
|
|
|
|
<view class="attach-list">
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="attach-item"
|
|
|
|
|
|
v-for="(file, index) in fileList"
|
|
|
|
|
|
:key="file.attId || file.fileId || index"
|
|
|
|
|
|
@click="fileClick(file)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="left">
|
|
|
|
|
|
<image
|
|
|
|
|
|
v-if="isImageFile(file)"
|
|
|
|
|
|
class="thumb"
|
|
|
|
|
|
:src="getFileUrl(file)"
|
|
|
|
|
|
mode="aspectFill"
|
|
|
|
|
|
></image>
|
|
|
|
|
|
<view v-else class="file-icon">文</view>
|
|
|
|
|
|
<view class="meta">
|
|
|
|
|
|
<text class="name">{{ file.name || '未命名附件' }}</text>
|
|
|
|
|
|
<text class="desc">
|
|
|
|
|
|
{{ (file.attType || '文件').toUpperCase() }}
|
|
|
|
|
|
<text v-if="formatFileSize(file.attSize)"> · {{ formatFileSize(file.attSize) }}</text>
|
|
|
|
|
|
</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<text class="preview-btn">{{ isImageFile(file) ? '预览' : '打开' }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="empty-page" v-else>
|
|
|
|
|
|
<text class="iconfont icon-wushuju"></text>
|
|
|
|
|
|
<text class="text">暂无详情数据</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="loading" v-else>
|
|
|
|
|
|
<text>加载中...</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import jyfParser from '@/components/jyf-parser/jyf-parser';
|
|
|
|
|
|
import { pubnoticeDetailApi } from '@/api/pubnotice.js';
|
|
|
|
|
|
import { HTTP_ADMIN_URL } from '@/config/app';
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
components: {
|
|
|
|
|
|
'jyf-parser': jyfParser,
|
|
|
|
|
|
},
|
|
|
|
|
|
dicts: ['sys_notice_type'],
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
HTTP_ADMIN_URL,
|
|
|
|
|
|
loading: false,
|
|
|
|
|
|
noticeId: '',
|
|
|
|
|
|
notice: {},
|
|
|
|
|
|
tagStyle: {
|
|
|
|
|
|
img: 'max-width:100%;height:auto;display:block;',
|
|
|
|
|
|
table: 'width:100%;border-collapse:collapse;',
|
|
|
|
|
|
video: 'max-width:100%;',
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
computed: {
|
|
|
|
|
|
fileList() {
|
|
|
|
|
|
return Array.isArray(this.notice?.files) ? this.notice.files : [];
|
|
|
|
|
|
},
|
|
|
|
|
|
imageFiles() {
|
|
|
|
|
|
return this.fileList
|
|
|
|
|
|
.filter((item) => this.isImageFile(item))
|
|
|
|
|
|
.map((item) => this.getFileUrl(item))
|
|
|
|
|
|
.filter(Boolean);
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
onLoad(options) {
|
|
|
|
|
|
this.noticeId = options.noticeId || options.id || '';
|
|
|
|
|
|
if (this.noticeId) this.fetchDetail();
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
async fetchDetail() {
|
|
|
|
|
|
this.loading = true;
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await pubnoticeDetailApi(this.noticeId);
|
|
|
|
|
|
this.notice = res?.data || {};
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: typeof e === 'string' ? e : '获取通知详情失败',
|
|
|
|
|
|
icon: 'none',
|
|
|
|
|
|
});
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
this.loading = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
getFilePath(item) {
|
|
|
|
|
|
if (!item) return '';
|
|
|
|
|
|
return item.attDir || item.sattDir || item.url || item.filePath || '';
|
|
|
|
|
|
},
|
|
|
|
|
|
getFileUrl(item) {
|
|
|
|
|
|
const path = this.getFilePath(item);
|
|
|
|
|
|
if (!path) return '';
|
|
|
|
|
|
if (/^https?:\/\//i.test(path)) return path;
|
|
|
|
|
|
const base = String(this.HTTP_ADMIN_URL || '').replace(/\/$/, '');
|
|
|
|
|
|
return `${base}/${String(path).replace(/^\//, '')}`;
|
|
|
|
|
|
},
|
|
|
|
|
|
isImageFile(item) {
|
|
|
|
|
|
const type = String(item?.attType || '').toLowerCase();
|
|
|
|
|
|
return (
|
|
|
|
|
|
['pic', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(type)
|
|
|
|
|
|
);
|
|
|
|
|
|
},
|
|
|
|
|
|
formatFileSize(size) {
|
|
|
|
|
|
const num = Number(size);
|
|
|
|
|
|
if (!num || Number.isNaN(num)) return '';
|
|
|
|
|
|
if (num < 1024) return `${num}B`;
|
|
|
|
|
|
if (num < 1024 * 1024) return `${(num / 1024).toFixed(1)}KB`;
|
|
|
|
|
|
if (num < 1024 * 1024 * 1024) return `${(num / 1024 / 1024).toFixed(1)}MB`;
|
|
|
|
|
|
return `${(num / 1024 / 1024 / 1024).toFixed(1)}GB`;
|
|
|
|
|
|
},
|
|
|
|
|
|
async fileClick(item) {
|
|
|
|
|
|
const current = this.getFileUrl(item);
|
|
|
|
|
|
if (!current) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '附件地址无效',
|
|
|
|
|
|
icon: 'none',
|
|
|
|
|
|
});
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (this.isImageFile(item)) {
|
|
|
|
|
|
uni.previewImage({
|
|
|
|
|
|
current,
|
|
|
|
|
|
urls: this.imageFiles,
|
|
|
|
|
|
fail: (e) => {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: e?.errMsg || '预览失败',
|
|
|
|
|
|
icon: 'none',
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
uni.showLoading({
|
|
|
|
|
|
title: '加载中...',
|
|
|
|
|
|
});
|
|
|
|
|
|
try {
|
|
|
|
|
|
const downloadRes = await new Promise((resolve, reject) => {
|
|
|
|
|
|
uni.downloadFile({
|
|
|
|
|
|
url: current,
|
|
|
|
|
|
success: (res) => resolve(res),
|
|
|
|
|
|
fail: reject,
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
if (downloadRes.statusCode !== 200) {
|
|
|
|
|
|
throw new Error('加载失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
await new Promise((resolve, reject) => {
|
|
|
|
|
|
uni.openDocument({
|
|
|
|
|
|
filePath: downloadRes.tempFilePath,
|
|
|
|
|
|
showMenu: true,
|
|
|
|
|
|
success: resolve,
|
|
|
|
|
|
fail: reject,
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: e?.errMsg || e?.message || '打开失败',
|
|
|
|
|
|
icon: 'none',
|
|
|
|
|
|
});
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
uni.hideLoading();
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss">
|
|
|
|
|
|
.notice-detail-page {
|
|
|
|
|
|
.content {
|
|
|
|
|
|
padding: 30rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.detail-card {
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.06);
|
|
|
|
|
|
padding: 24rpx 26rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.title-section {
|
|
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.detail-title {
|
|
|
|
|
|
font-size: 30rpx;
|
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
line-height: 1.4;
|
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.info-list {
|
|
|
|
|
|
.row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
margin-bottom: 14rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.label {
|
|
|
|
|
|
width: 170rpx;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.value {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
word-break: break-word;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.remark-value {
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.content-box {
|
|
|
|
|
|
margin-top: 10rpx;
|
|
|
|
|
|
padding-top: 20rpx;
|
|
|
|
|
|
border-top: 1rpx solid #f5f5f5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.attach-box {
|
|
|
|
|
|
margin-top: 24rpx;
|
|
|
|
|
|
padding-top: 20rpx;
|
|
|
|
|
|
border-top: 1rpx solid #f5f5f5;
|
|
|
|
|
|
|
|
|
|
|
|
.attach-title {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
margin-bottom: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.attach-list {
|
|
|
|
|
|
.attach-item {
|
|
|
|
|
|
min-height: 108rpx;
|
|
|
|
|
|
border: 1rpx solid #f0f0f0;
|
|
|
|
|
|
border-radius: 10rpx;
|
|
|
|
|
|
padding: 14rpx 16rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
margin-bottom: 12rpx;
|
|
|
|
|
|
background: #fafafa;
|
|
|
|
|
|
|
|
|
|
|
|
.left {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.thumb {
|
|
|
|
|
|
width: 72rpx;
|
|
|
|
|
|
height: 72rpx;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
background-color: #f5f5f5;
|
|
|
|
|
|
margin-right: 14rpx;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.file-icon {
|
|
|
|
|
|
width: 72rpx;
|
|
|
|
|
|
height: 72rpx;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
background: #eef4ff;
|
|
|
|
|
|
color: #409eff;
|
|
|
|
|
|
font-size: 30rpx;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
margin-right: 14rpx;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.meta {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.name {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
line-height: 1.4;
|
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.desc {
|
|
|
|
|
|
margin-top: 6rpx;
|
|
|
|
|
|
font-size: 20rpx;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.preview-btn {
|
|
|
|
|
|
margin-left: 16rpx;
|
|
|
|
|
|
color: #409eff;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.empty-page {
|
|
|
|
|
|
margin-top: 120rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
|
|
|
|
|
|
.iconfont {
|
|
|
|
|
|
font-size: 80rpx;
|
|
|
|
|
|
margin-bottom: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.text {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.empty {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
line-height: 2;
|
|
|
|
|
|
padding: 30rpx 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.loading {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|
|
|
|
|
|
|