<!-- EnterpriseNews:详情只读面板(含互动) -->
|
<template>
|
<el-descriptions :column="2" border>
|
<el-descriptions-item label="新闻编号">{{ row.newsNo || "—" }}</el-descriptions-item>
|
<el-descriptions-item label="发布状态">
|
<el-tag :type="publishStatusTag(row.publishStatus)" size="small">
|
{{ publishStatusLabel(row.publishStatus) }}
|
</el-tag>
|
</el-descriptions-item>
|
<el-descriptions-item label="新闻分类">
|
<span class="type-badge" :style="{ color: newsTypeColor(row.newsType) }">
|
{{ newsTypeLabel(row.newsType) }}
|
</span>
|
</el-descriptions-item>
|
<el-descriptions-item label="排版模板">{{ layoutTemplateLabel(row.layoutTemplate) }}</el-descriptions-item>
|
<el-descriptions-item label="标题" :span="2">{{ row.title || "—" }}</el-descriptions-item>
|
<el-descriptions-item label="摘要" :span="2">{{ row.summary || "—" }}</el-descriptions-item>
|
<el-descriptions-item label="阅读范围">{{ readScopeLabel(row.readScope) }}</el-descriptions-item>
|
<el-descriptions-item label="阅读率">
|
{{ readRate(row) }}%(未读 {{ unreadCount }} 人)
|
</el-descriptions-item>
|
<el-descriptions-item label="编辑权限">{{ publishRoleLabel(row.editorRole) }}</el-descriptions-item>
|
<el-descriptions-item label="审核角色">{{ publishRoleLabel(row.reviewerRole) }}</el-descriptions-item>
|
<el-descriptions-item label="发布人">{{ row.publisherName || "—" }}</el-descriptions-item>
|
<el-descriptions-item label="发布时间">{{ row.publishTime || "—" }}</el-descriptions-item>
|
<el-descriptions-item label="当前版本">v{{ row.versionNo || 1 }}</el-descriptions-item>
|
<el-descriptions-item label="需阅读确认">
|
{{ row.requireReadConfirm ? "是" : "否" }}
|
</el-descriptions-item>
|
</el-descriptions>
|
|
<el-divider content-position="left">正文内容</el-divider>
|
<div v-if="row.contentHtml" class="news-html-body" v-html="row.contentHtml" />
|
<el-empty v-else description="暂无正文" :image-size="48" />
|
|
<template v-if="row.mediaList?.length">
|
<el-divider content-position="left">图集 / 视频</el-divider>
|
<div class="media-grid">
|
<div v-for="(m, i) in row.mediaList" :key="i" class="media-item">
|
<el-tag size="small" type="info">{{ m.type === "video" ? "视频" : "图片" }}</el-tag>
|
<span class="media-name">{{ m.name }}</span>
|
</div>
|
</div>
|
</template>
|
|
<el-divider content-position="left">附件</el-divider>
|
<template v-if="row.attachmentList?.length">
|
<el-tag
|
v-for="(f, i) in row.attachmentList"
|
:key="i"
|
class="file-tag"
|
type="info"
|
@click="openFile(f)"
|
>
|
{{ f.name }}
|
</el-tag>
|
</template>
|
<el-empty v-else description="暂无附件" :image-size="48" />
|
|
<template v-if="row.newsType === 'culture' && row.publishStatus === 'published'">
|
<el-divider content-position="left">互动(点赞 {{ likeCount }} · 评论 {{ commentCount }})</el-divider>
|
<div class="interaction-bar">
|
<el-button type="primary" plain size="small" @click="$emit('like')">
|
{{ likedByMe ? "取消点赞" : "点赞" }}
|
</el-button>
|
</div>
|
<el-input
|
v-model="commentDraft"
|
type="textarea"
|
:rows="2"
|
maxlength="300"
|
show-word-limit
|
placeholder="写下你的评论…"
|
class="mb8"
|
/>
|
<el-button type="primary" size="small" @click="submitComment">发表评论</el-button>
|
<el-timeline v-if="row.comments?.length" class="comment-timeline mt12">
|
<el-timeline-item v-for="c in row.comments" :key="c.id" :timestamp="c.time">
|
<strong>{{ c.name }}</strong>:{{ c.content }}
|
</el-timeline-item>
|
</el-timeline>
|
<el-empty v-else description="暂无评论" :image-size="40" />
|
</template>
|
</template>
|
|
<script setup>
|
import { computed, ref } from "vue";
|
import {
|
newsTypeLabel,
|
newsTypeColor,
|
publishStatusLabel,
|
publishStatusTag,
|
layoutTemplateLabel,
|
readScopeLabel,
|
publishRoleLabel,
|
readRate,
|
getUnreadEmployees,
|
} from "../enterpriseNewsUtils.js";
|
|
const props = defineProps({
|
row: { type: Object, default: () => ({}) },
|
});
|
|
const emit = defineEmits(["like", "comment"]);
|
|
const commentDraft = ref("");
|
|
const unreadCount = computed(() => getUnreadEmployees(props.row).length);
|
const likeCount = computed(() => props.row?.likes?.length || 0);
|
const commentCount = computed(() => props.row?.comments?.length || 0);
|
const likedByMe = computed(() => (props.row?.likes || []).some((l) => l.userId === "u1"));
|
|
function openFile(f) {
|
const url = f?.url || f?.downloadURL;
|
if (url) window.open(url, "_blank");
|
}
|
|
function submitComment() {
|
emit("comment", commentDraft.value);
|
commentDraft.value = "";
|
}
|
</script>
|
|
<style scoped>
|
.type-badge {
|
font-weight: 600;
|
}
|
.news-html-body {
|
padding: 12px 16px;
|
background: var(--el-fill-color-light);
|
border-radius: 6px;
|
line-height: 1.7;
|
max-height: 320px;
|
overflow-y: auto;
|
}
|
.media-grid {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 12px;
|
}
|
.media-item {
|
display: flex;
|
align-items: center;
|
gap: 8px;
|
padding: 8px 12px;
|
background: var(--el-fill-color-lighter);
|
border-radius: 4px;
|
}
|
.media-name {
|
font-size: 13px;
|
}
|
.file-tag {
|
margin: 0 8px 8px 0;
|
cursor: pointer;
|
}
|
.interaction-bar {
|
margin-bottom: 8px;
|
}
|
.comment-timeline {
|
max-height: 200px;
|
overflow-y: auto;
|
}
|
.mb8 {
|
margin-bottom: 8px;
|
}
|
.mt12 {
|
margin-top: 12px;
|
}
|
</style>
|