Files
sgxt_web/src/views/forumPost/components/theRight.vue
2025-12-13 17:18:20 +08:00

496 lines
11 KiB
Vue

<template>
<div class="app-container" v-show="cs">
<div class="publish-section"><el-button type="primary" @click="handleEdit()">发布帖子</el-button></div>
<div v-if="list.length > 0" v-infinite-scroll="load">
<div class="post-card" v-for="(item, index) in list" :key="index">
<div class="post-content" @click="handleOpen(item)" @mouseenter="showActions[index] = true"
@mouseleave="showActions[index] = false">
<div class="post-header">
<div class="post-title">
{{ item.title || '无标题' }}
</div>
<div class="post-meta">
<div class="post-time" style="margin-right: 20px;" title="发布人">{{ item.fbrxm || '暂无发布人' }}</div>
<div class="post-time" title="发布时间">{{ item.time || '暂无时间' }}</div>
</div>
</div>
<div class="post-body">
<div class="post-text">
{{ item.content }}
</div>
<div class="post-images">
<div class="image-list">
<div v-for="(img, imgIndex) in item.tp" :key="imgIndex" class="image-item"
v-if="item.tp && item.tp.length > 0">
<el-image :src="setAddress(img)" show-progress>
<template #error>
<div class="image-slot error">
<img src="@/assets/images/default_male.png" width="80" height="80" />
</div>
</template>
</el-image>
</div>
</div>
</div>
</div>
</div>
<div style="display: flex;justify-content: flex-end;margin-bottom: 10px;"
v-if="sfzh == item.fbrsfzh || isShiQingZhi()">
<el-button type="text" size="small" class="action-btn edit-btn" @click.stop="handleEdit(item)">
<el-icon>
<Edit />
</el-icon> 修改
</el-button>
<el-button type="text" size="small" class="action-btn delete-btn" @click.stop="handleDelete(item)">
<el-icon>
<Delete />
</el-icon> 删除
</el-button>
<el-button v-if="isShiQingZhi()" type="text" size="small" class="action-btn delete-btn"
@click.stop="handleSetTop(item)">
<el-icon>
<Top />
</el-icon> {{ item.sfzd == 1 ? '取消置顶' : '置顶' }}
</el-button>
</div>
</div>
</div>
<!-- 空数据占位 -->
<div v-else class="empty-data">
<div class="empty-icon">
<el-icon size="64">
<Document />
</el-icon>
</div>
<div class="empty-text">暂无帖子数据</div>
<div class="empty-hint">点击上方按钮发布第一条帖子吧</div>
</div>
</div>
<Release v-model="showModel" :ItemData="ItemData" @SaveReport="SaveReport" title="帖子发布" :showCancel="false"
:heightNumber="436"></Release>
<Particulars ref="particulars" />
</template>
<script setup>
import Release from './release.vue'
import { setAddress } from '@/utils/tools'
import { ref, reactive, onMounted } from 'vue'
import { tbGsxtXxltSelectPage, tbGsxtXxltDelete, tbGsxtXxltHfid, tbGsxtXxltUpdate } from '@/api/tbGsxtXxltHf'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Edit, Delete, Document } from '@element-plus/icons-vue'
import { getItem } from '@/utils/storage.js'
import Particulars from "./particulars.vue";
import { useRouter, useRoute } from 'vue-router'
import { isShiQingZhi } from "@/utils/auth.js"
const route = useRoute()
const particulars = ref()
const showModel = ref(false)
const listQuery = reactive({
pageCurrent: 1,
pageSize: 10,
})
const total = ref(0)
const list = ref([])
const showActions = ref({})
const sfzh = ref()
const ItemData = ref()
const cs = ref(false)//需要删除
onMounted(() => {
sfzh.value = getItem('idEntityCard')
SaveReport()
if (route.query.id) {
tbGsxtXxltHfid(route.query.id).then(res => {
ItemData.value = res
particulars.value.init(ItemData.value)
cs.value = true
})
} else {
cs.value = true
}
})
const SaveReport = () => {
tbGsxtXxltSelectPage(listQuery).then(res => {
// 使用可选链操作符和箭头函数隐式返回优化代码
const data = (res.records || []).map(item => ({
...item,
tp: item.tp ? item.tp.split(',') : []
}))
total.value = res.total || 0
// 初始化所有操作按钮为隐藏状态
const actions = {}
list.value = data
list.value.forEach((_, index) => {
actions[index] = false
})
showActions.value = actions
})
}
const handleOpen = (item) => {
particulars.value.init(item);
}
// 修改帖子
const handleEdit = (item) => {
ItemData.value = item
// 这里可以添加实际的修改逻辑
showModel.value = true
}
// 删除帖子
const handleDelete = (item) => {
ElMessageBox.confirm(
`确定要删除帖子「${item.title}」吗?`,
'删除确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
tbGsxtXxltDelete(item.id).then(res => {
if (res) {
ElMessage({ message: `帖子「${item.title}」已删除`, type: 'success' })
SaveReport() // 删除后刷新列表
} else {
ElMessage({ message: `删除帖子「${item.title}」失败:${res.msg || '未知错误'}`, type: 'error' })
}
})
}).catch(() => {
ElMessage({ message: '已取消删除', type: 'info' })
})
}
/** 置顶帖子 */
const handleSetTop = (item) => {
ElMessageBox.confirm(
`确定要置顶帖子「${item.title}」吗?`,
'置顶确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(async () => {
const detail = await tbGsxtXxltHfid(item.id)
detail.sfzd = item.sfzd === 1 ? 0 : 1
tbGsxtXxltUpdate(detail).then(res => {
if (res) {
ElMessage({ message: `帖子「${item.title}」已置顶`, type: 'success' })
SaveReport() // 置顶后刷新列表
} else {
ElMessage({ message: `置顶帖子「${item.title}」失败:${res.msg || '未知错误'}`, type: 'error' })
}
})
}).catch(() => {
ElMessage({ message: '已取消置顶', type: 'info' })
})
}
const load = () => {
if (listQuery.pageCurrent * listQuery.pageSize < total.value) {
listQuery.pageCurrent++
SaveReport()
}
}
</script>
<style scoped lang="scss">
// 主容器样式
.app-container {
padding: 16px;
color: #333;
font-size: 14px;
line-height: 1.5;
background-color: #f5f7fa;
min-height: 100%;
}
// 发布按钮区域
.publish-section {
margin-bottom: 20px;
display: flex;
justify-content: flex-end;
}
// 帖子卡片样式
.post-card {
background: white;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
&:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
}
// 帖子内容区域
.post-content {
padding: 16px;
cursor: pointer;
}
// 帖子头部
.post-header {
display: flex;
justify-content: space-between;
margin-bottom: 12px;
align-items: flex-start;
}
// 帖子标题
.post-title {
font-size: 18px;
font-weight: 600;
color: #409eff;
margin-right: 16px;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
transition: color 0.3s ease;
&:hover {
color: #409eff;
}
}
// 帖子元信息
.post-meta {
flex-shrink: 0;
display: flex;
justify-content: space-between;
}
// 发布时间
.post-time {
color: #909399;
font-size: 12px;
white-space: nowrap;
}
// 帖子主体
.post-body {
position: relative;
}
// 帖子文本内容
.post-text {
color: #606266;
font-size: 14px;
line-height: 1.6;
margin-bottom: 12px;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
// 帖子图片容器
.post-images {
margin-top: 8px;
}
// 图片列表
.image-list {
display: flex;
flex-wrap: wrap;
margin: -4px;
}
// 图片项
.image-item {
margin: 4px;
width: 100px;
height: 160px;
position: relative;
overflow: hidden;
border-radius: 4px;
flex-shrink: 0;
}
// 帖子图片
.post-image {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
&:hover {
transform: scale(1.05);
}
}
// 更多图片提示
.image-more {
width: 80px;
height: 80px;
background: rgba(0, 0, 0, 0.6);
color: white;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
font-size: 12px;
margin: 4px;
}
// 操作按钮容器
.post-actions {
position: absolute;
right: 16px;
bottom: 16px;
background: white;
padding: 8px;
border-radius: 6px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
z-index: 10;
display: flex;
gap: 8px;
transform: translateY(10px);
}
// 操作按钮显示状态
.post-actions-visible {
opacity: 1;
visibility: visible;
}
// 操作按钮基础样式
.action-btn {
display: flex;
align-items: center;
gap: 4px;
padding: 4px 12px;
border-radius: 4px;
transition: all 0.3s ease;
font-size: 12px;
color: #606266;
background: #f5f7fa;
&:hover {
transform: translateY(-1px);
}
}
// 修改按钮样式
.edit-btn:hover {
color: #409eff;
background: #ecf5ff;
}
// 删除按钮样式
.delete-btn:hover {
color: #f56c6c;
background: #fef0f0;
}
// 空数据样式
.empty-data {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60px 20px;
background: white;
border-radius: 8px;
color: #909399;
text-align: center;
margin-top: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
min-height: 300px;
}
.empty-icon {
margin-bottom: 16px;
color: #c0c4cc;
}
.empty-text {
font-size: 16px;
margin-bottom: 8px;
color: #606266;
}
.empty-hint {
font-size: 14px;
color: #909399;
}
// 移动端适配
@media (max-width: 768px) {
.app-container {
padding: 12px;
}
.post-card {
margin-bottom: 12px;
}
.post-content {
padding: 12px;
}
.post-title {
font-size: 16px;
}
.post-text {
font-size: 13px;
-webkit-line-clamp: 2;
}
.image-item {
width: 60px;
height: 60px;
}
.image-more {
width: 60px;
height: 60px;
}
.post-actions {
right: 12px;
padding: 6px;
}
.action-btn {
padding: 3px 8px;
font-size: 11px;
}
.empty-data {
padding: 40px 16px;
min-height: 250px;
}
.empty-icon {
font-size: 48px;
}
.empty-text {
font-size: 14px;
}
.empty-hint {
font-size: 12px;
}
}
</style>