|
|
|
|
@ -1,19 +1,33 @@
|
|
|
|
|
<template>
|
|
|
|
|
<!-- 主卡片容器,包含整个说说列表页面内容 -->
|
|
|
|
|
<el-card class="main-card">
|
|
|
|
|
<!-- 页面标题,显示当前路由名称 -->
|
|
|
|
|
<div class="title">{{ this.$route.name }}</div>
|
|
|
|
|
|
|
|
|
|
<!-- 状态筛选菜单区域,用于筛选不同状态的说说 -->
|
|
|
|
|
<div class="status-menu">
|
|
|
|
|
<span>状态</span>
|
|
|
|
|
<!-- 全部状态筛选按钮 -->
|
|
|
|
|
<span @click="changeStatus(null)" :class="isActive(null)">全部</span>
|
|
|
|
|
<!-- 公开状态筛选按钮 -->
|
|
|
|
|
<span @click="changeStatus(1)" :class="isActive(1)"> 公开 </span>
|
|
|
|
|
<!-- 私密状态筛选按钮 -->
|
|
|
|
|
<span @click="changeStatus(2)" :class="isActive(2)"> 私密 </span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 当说说列表为空时显示空状态提示 -->
|
|
|
|
|
<el-empty v-if="talks == null" description="暂无说说" />
|
|
|
|
|
|
|
|
|
|
<!-- 说说列表,遍历展示每条说说 -->
|
|
|
|
|
<div class="talk-item" v-for="item of talks" :key="item.id">
|
|
|
|
|
<div class="user-info-wrapper">
|
|
|
|
|
<!-- 用户头像 -->
|
|
|
|
|
<el-avatar class="user-avatar" :src="item.avatar" :size="36" />
|
|
|
|
|
<div class="user-detail-wrapper">
|
|
|
|
|
<!-- 用户名和操作下拉菜单 -->
|
|
|
|
|
<div class="user-nickname">
|
|
|
|
|
<div>{{ item.nickname }}</div>
|
|
|
|
|
<!-- 操作下拉菜单(编辑/删除) -->
|
|
|
|
|
<el-dropdown trigger="click" @command="handleCommand">
|
|
|
|
|
<i class="el-icon-more" style="color: #333; cursor: pointer" />
|
|
|
|
|
<el-dropdown-menu slot="dropdown">
|
|
|
|
|
@ -22,12 +36,18 @@
|
|
|
|
|
</el-dropdown-menu>
|
|
|
|
|
</el-dropdown>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 发布时间和状态标签(置顶/私密) -->
|
|
|
|
|
<div class="time">
|
|
|
|
|
{{ item.createTime | dateTime }}
|
|
|
|
|
{{ item.createTime | dateTime }} <!-- 时间格式化过滤器 -->
|
|
|
|
|
<span class="top" v-if="item.isTop == 1"> <i class="iconfont el-icon-myzhiding" /> 置顶 </span>
|
|
|
|
|
<span class="secret" v-if="item.status == 2"> <i class="iconfont el-icon-mymima" /> 私密 </span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 说说内容,v-html渲染富文本内容 -->
|
|
|
|
|
<div class="talk-content" v-html="item.content" />
|
|
|
|
|
|
|
|
|
|
<!-- 说说图片列表,有图片时展示 -->
|
|
|
|
|
<el-row :gutter="4" class="talk-images" v-if="item.imgs">
|
|
|
|
|
<el-col :md="8" :cols="6" v-for="(img, index) of item.imgs" :key="index">
|
|
|
|
|
<el-image class="images-items" :src="img" :preview-src-list="previews" />
|
|
|
|
|
@ -36,15 +56,19 @@
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 分页组件 -->
|
|
|
|
|
<el-pagination
|
|
|
|
|
:hide-on-single-page="false"
|
|
|
|
|
class="pagination-container"
|
|
|
|
|
@size-change="sizeChange"
|
|
|
|
|
@current-change="currentChange"
|
|
|
|
|
:current-page="current"
|
|
|
|
|
:page-size="size"
|
|
|
|
|
:total="count"
|
|
|
|
|
layout="prev, pager, next" />
|
|
|
|
|
:hide-on-single-page="false" <!-- 即使只有一页也显示分页 -->
|
|
|
|
|
class="pagination-container"
|
|
|
|
|
@size-change="sizeChange" <!-- 每页条数变化事件 -->
|
|
|
|
|
@current-change="currentChange" <!-- 当前页码变化事件 -->
|
|
|
|
|
:current-page="current" <!-- 当前页码 -->
|
|
|
|
|
:page-size="size" <!-- 每页条数 -->
|
|
|
|
|
:total="count" <!-- 总条数 -->
|
|
|
|
|
layout="prev, pager, next" /> <!-- 分页布局:上一页、页码、下一页 -->
|
|
|
|
|
|
|
|
|
|
<!-- 删除确认对话框 -->
|
|
|
|
|
<el-dialog :visible.sync="isdelete" width="30%">
|
|
|
|
|
<div class="dialog-title-container" slot="title"><i class="el-icon-warning" style="color: #ff9900" />提示</div>
|
|
|
|
|
<div style="font-size: 1rem">是否删除该说说?</div>
|
|
|
|
|
@ -58,90 +82,105 @@
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
export default {
|
|
|
|
|
// 页面创建时执行的钩子函数
|
|
|
|
|
created() {
|
|
|
|
|
// 从Vuex中获取保存的当前页码,用于页面刷新后保持分页状态
|
|
|
|
|
this.current = this.$store.state.pageState.talkList
|
|
|
|
|
// 加载说说列表数据
|
|
|
|
|
this.listTalks()
|
|
|
|
|
},
|
|
|
|
|
data: function () {
|
|
|
|
|
return {
|
|
|
|
|
current: 1,
|
|
|
|
|
size: 5,
|
|
|
|
|
count: 0,
|
|
|
|
|
status: null,
|
|
|
|
|
isdelete: false,
|
|
|
|
|
talks: [],
|
|
|
|
|
previews: [],
|
|
|
|
|
talkId: null
|
|
|
|
|
current: 1, // 当前页码
|
|
|
|
|
size: 5, // 每页显示条数
|
|
|
|
|
count: 0, // 总记录数
|
|
|
|
|
status: null, // 筛选状态(null:全部,1:公开,2:私密)
|
|
|
|
|
isdelete: false, // 删除对话框显示状态
|
|
|
|
|
talks: [], // 说说列表数据
|
|
|
|
|
previews: [], // 图片预览列表
|
|
|
|
|
talkId: null // 当前操作的说说ID(用于编辑/删除)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
// 处理下拉菜单命令(编辑/删除)
|
|
|
|
|
handleCommand(command) {
|
|
|
|
|
// 分割命令字符串,获取操作类型和说说ID
|
|
|
|
|
var arr = command.split(',')
|
|
|
|
|
this.talkId = arr[1]
|
|
|
|
|
switch (arr[0]) {
|
|
|
|
|
case '1':
|
|
|
|
|
// 编辑操作:跳转到说说编辑页
|
|
|
|
|
this.$router.push({ path: '/talks/' + this.talkId })
|
|
|
|
|
break
|
|
|
|
|
case '2':
|
|
|
|
|
// 删除操作:显示删除确认对话框
|
|
|
|
|
this.isdelete = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 获取说说列表数据
|
|
|
|
|
listTalks() {
|
|
|
|
|
this.axios
|
|
|
|
|
.get('/api/admin/talks', {
|
|
|
|
|
params: {
|
|
|
|
|
current: this.current,
|
|
|
|
|
size: this.size,
|
|
|
|
|
status: this.status
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.then(({ data }) => {
|
|
|
|
|
this.talks = data.data.records
|
|
|
|
|
this.talks.forEach((item) => {
|
|
|
|
|
if (item.imgs) {
|
|
|
|
|
this.previews.push(...item.imgs)
|
|
|
|
|
.get('/api/admin/talks', {
|
|
|
|
|
params: {
|
|
|
|
|
current: this.current, // 当前页码
|
|
|
|
|
size: this.size, // 每页条数
|
|
|
|
|
status: this.status // 状态筛选条件
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
this.count = data.data.count
|
|
|
|
|
})
|
|
|
|
|
.then(({ data }) => {
|
|
|
|
|
this.talks = data.data.records // 赋值说说列表
|
|
|
|
|
// 收集所有说说的图片用于预览
|
|
|
|
|
this.talks.forEach((item) => {
|
|
|
|
|
if (item.imgs) {
|
|
|
|
|
this.previews.push(...item.imgs)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
this.count = data.data.count // 赋值总记录数
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 每页条数变化时触发
|
|
|
|
|
sizeChange(size) {
|
|
|
|
|
this.previews = []
|
|
|
|
|
this.size = size
|
|
|
|
|
this.listTalks()
|
|
|
|
|
this.previews = [] // 清空图片预览列表
|
|
|
|
|
this.size = size // 更新每页条数
|
|
|
|
|
this.listTalks() // 重新加载列表
|
|
|
|
|
},
|
|
|
|
|
// 当前页码变化时触发
|
|
|
|
|
currentChange(current) {
|
|
|
|
|
this.previews = []
|
|
|
|
|
this.current = current
|
|
|
|
|
this.previews = [] // 清空图片预览列表
|
|
|
|
|
this.current = current // 更新当前页码
|
|
|
|
|
// 将当前页码保存到Vuex,用于页面刷新后恢复
|
|
|
|
|
this.$store.commit('updateTalkListPageState', current)
|
|
|
|
|
this.listTalks()
|
|
|
|
|
this.listTalks() // 重新加载列表
|
|
|
|
|
},
|
|
|
|
|
// 切换状态筛选条件
|
|
|
|
|
changeStatus(status) {
|
|
|
|
|
this.current = 1
|
|
|
|
|
this.previews = []
|
|
|
|
|
this.status = status
|
|
|
|
|
this.listTalks()
|
|
|
|
|
this.current = 1 // 重置为第一页
|
|
|
|
|
this.previews = [] // 清空图片预览列表
|
|
|
|
|
this.status = status // 更新筛选状态
|
|
|
|
|
this.listTalks() // 重新加载列表
|
|
|
|
|
},
|
|
|
|
|
// 确认删除说说
|
|
|
|
|
deleteTalk() {
|
|
|
|
|
this.axios.delete('/api/admin/talks', { data: [this.talkId] }).then(({ data }) => {
|
|
|
|
|
if (data.flag) {
|
|
|
|
|
if (data.flag) { // 删除成功
|
|
|
|
|
this.$notify.success({
|
|
|
|
|
title: '成功',
|
|
|
|
|
message: data.message
|
|
|
|
|
})
|
|
|
|
|
this.listTalks()
|
|
|
|
|
} else {
|
|
|
|
|
this.listTalks() // 重新加载列表
|
|
|
|
|
} else { // 删除失败
|
|
|
|
|
this.$notify.error({
|
|
|
|
|
title: '失败',
|
|
|
|
|
message: data.message
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
this.isdelete = false
|
|
|
|
|
this.isdelete = false // 关闭删除对话框
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
computed: {
|
|
|
|
|
// 判断当前状态筛选是否激活,用于设置样式
|
|
|
|
|
isActive() {
|
|
|
|
|
return function (status) {
|
|
|
|
|
return this.status == status ? 'active-status' : 'status'
|
|
|
|
|
@ -152,6 +191,7 @@ export default {
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
/* 状态菜单样式 */
|
|
|
|
|
.status-menu {
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
margin-top: 40px;
|
|
|
|
|
@ -160,17 +200,21 @@ export default {
|
|
|
|
|
.status-menu span {
|
|
|
|
|
margin-right: 24px;
|
|
|
|
|
}
|
|
|
|
|
/* 未激活状态样式 */
|
|
|
|
|
.status {
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
/* 激活状态样式 */
|
|
|
|
|
.active-status {
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
color: #333;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
}
|
|
|
|
|
/* 说说项样式,除第一个外添加顶部margin */
|
|
|
|
|
.talk-item:not(:first-child) {
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
}
|
|
|
|
|
/* 说说项容器样式 */
|
|
|
|
|
.talk-item {
|
|
|
|
|
padding: 16px 20px;
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
@ -178,60 +222,67 @@ export default {
|
|
|
|
|
box-shadow: 0 3px 8px 6px rgb(7 17 27 / 6%);
|
|
|
|
|
transition: all 0.3s ease 0s;
|
|
|
|
|
}
|
|
|
|
|
/* 说说项 hover 效果 */
|
|
|
|
|
.talk-item:hover {
|
|
|
|
|
box-shadow: 0 5px 10px 8px rgb(7 17 27 / 16%);
|
|
|
|
|
transform: translateY(-3px);
|
|
|
|
|
}
|
|
|
|
|
/* 用户信息容器 */
|
|
|
|
|
.user-info-wrapper {
|
|
|
|
|
width: 100%;
|
|
|
|
|
display: flex;
|
|
|
|
|
}
|
|
|
|
|
/* 用户头像样式 */
|
|
|
|
|
.user-avatar {
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
}
|
|
|
|
|
.user-avatar {
|
|
|
|
|
transition: all 0.5s;
|
|
|
|
|
}
|
|
|
|
|
/* 头像 hover 旋转效果 */
|
|
|
|
|
.user-avatar:hover {
|
|
|
|
|
transform: rotate(360deg);
|
|
|
|
|
}
|
|
|
|
|
/* 用户详情容器 */
|
|
|
|
|
.user-detail-wrapper {
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
/* 用户名和操作按钮容器 */
|
|
|
|
|
.user-nickname {
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
}
|
|
|
|
|
.user-sign {
|
|
|
|
|
margin-left: 4px;
|
|
|
|
|
}
|
|
|
|
|
/* 时间和状态标签样式 */
|
|
|
|
|
.time {
|
|
|
|
|
color: #999;
|
|
|
|
|
margin-top: 2px;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
}
|
|
|
|
|
/* 置顶标签样式 */
|
|
|
|
|
.top {
|
|
|
|
|
color: #ff7242;
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
}
|
|
|
|
|
/* 私密标签样式 */
|
|
|
|
|
.secret {
|
|
|
|
|
color: #999;
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
}
|
|
|
|
|
/* 说说内容样式 */
|
|
|
|
|
.talk-content {
|
|
|
|
|
margin-top: 8px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
line-height: 26px;
|
|
|
|
|
white-space: pre-line;
|
|
|
|
|
word-wrap: break-word;
|
|
|
|
|
white-space: pre-line; /* 保留换行符 */
|
|
|
|
|
word-wrap: break-word; /* 自动换行 */
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
}
|
|
|
|
|
/* 图片列表样式 */
|
|
|
|
|
.talk-images {
|
|
|
|
|
margin-top: 8px;
|
|
|
|
|
}
|
|
|
|
|
/* 图片项样式 */
|
|
|
|
|
.images-items {
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
object-fit: cover;
|
|
|
|
|
@ -239,4 +290,4 @@ export default {
|
|
|
|
|
width: 100%;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
</style>
|