YingXingAI/pages/notes/index.vue

467 lines
11 KiB
Vue
Raw Normal View History

2025-07-04 16:04:01 +08:00
<template>
2025-07-22 09:39:42 +08:00
<view class="notes-page">
<PageHeader title="留言板" :is-back="false" :border-bottom="false" />
<view class="custom-tabs-box">
<u-tabs
:list="tabList"
:current="tabCurrent"
@change="onTabChange"
:is-scroll="false"
:height="80"
:font-size="28"
active-color="#4A6CF7"
inactive-color="#333333"
:bar-width="120"
:bar-height="4"
bg-color="#ffffff"
:item-width="200"
></u-tabs>
<view class="space"></view>
</view>
<!-- 内容区域包装器 -->
2025-07-22 09:39:42 +08:00
<view class="content-wrapper">
<!-- 留言列表 -->
2025-07-04 16:04:01 +08:00
<scroll-view class="message-list" scroll-y>
<view v-for="(item, index) in currentMessages" :key="index">
<u-swipe-action
:options="swipeOptions"
:show="item.show"
:index="index"
@click="handleSwipeClick"
2025-07-22 09:39:42 +08:00
@open="(e) => handleSwipeOpen(e, index)"
@close="(e) => handleSwipeClose(e, index)"
@content-click="() => closeOther(index)"
:btn-width="80"
:disabled="false"
>
<view class="message-item">
<view class="message-header">
<view class="user-info">
2025-07-22 09:39:42 +08:00
<image
class="avatar"
:src="item.avatar || defaultAvatar"
></image>
<text class="username">{{ item.username }}</text>
</view>
2025-07-22 09:39:42 +08:00
<view class="message-time">{{ item.time }}</view>
</view>
2025-07-22 09:39:42 +08:00
<view class="message-content">
<view class="question">
<view class="question-icon"></view>
2025-07-22 09:39:42 +08:00
<view class="question-text">{{ item.question }}</view>
</view>
2025-07-22 09:39:42 +08:00
<view
class="reply-button"
@click.stop="handleReply(item)"
v-if="!item.reply"
>
<u-icon name="chat" color="#4a6cf7" size="16"></u-icon>
<text>回复</text>
</view>
2025-07-22 09:39:42 +08:00
<view class="reply-content" v-if="item.reply">
<view class="reply-header">
<view class="reply-icon"></view>
<view class="reply-info">
2025-07-22 09:39:42 +08:00
<text>{{ item.replyUser }}</text>
</view>
</view>
2025-07-22 09:39:42 +08:00
<view
class="reply-text"
:class="{ expanded: item.expanded }"
>{{ item.reply }}</view
>
<view
class="expand-button"
v-if="item.reply.length > 100"
@click.stop="toggleExpand(item)"
>
{{ item.expanded ? "收起" : "展开" }}
<u-icon
:name="item.expanded ? 'arrow-up' : 'arrow-down'"
size="12"
></u-icon>
</view>
</view>
2025-07-22 09:39:42 +08:00
<view
class="reply-button"
@click.stop="handleReply(item)"
v-if="item.reply"
>
<u-icon name="chat" color="#4a6cf7" size="16"></u-icon>
<text>回复</text>
</view>
</view>
</view>
</u-swipe-action>
2025-07-04 16:04:01 +08:00
</view>
2025-07-22 09:39:42 +08:00
<!-- 无数据提示 -->
2025-07-04 16:04:01 +08:00
<view class="empty-tip" v-if="currentMessages.length === 0">
暂无留言数据
</view>
</scroll-view>
2025-07-22 09:39:42 +08:00
</view>
<!-- 使用TabBar组件 -->
2025-07-04 16:04:01 +08:00
<TabBar :currentPath="'/pages/notes/index'" @change="handleTabChange" />
2025-07-22 09:39:42 +08:00
<!-- 开发中提示弹窗 -->
2025-07-04 16:04:01 +08:00
<u-modal
v-model="showDevModal"
:show-cancel-button="false"
title="提示"
content="该功能正在开发中,敬请期待!"
@confirm="showDevModal = false"
></u-modal>
2025-07-22 09:39:42 +08:00
</view>
2025-07-04 16:04:01 +08:00
</template>
<script>
2025-07-22 09:39:42 +08:00
import TabBar from "@/components/TabBar.vue";
import PageHeader from "@/components/PageHeader.vue";
2025-07-04 16:04:01 +08:00
export default {
2025-07-22 09:39:42 +08:00
name: "NotesPage",
2025-07-04 16:04:01 +08:00
components: {
2025-07-22 09:39:42 +08:00
TabBar,
PageHeader,
2025-07-04 16:04:01 +08:00
},
data() {
return {
2025-07-22 09:39:42 +08:00
tabList: [{ name: "未回复" }, { name: "已回复" }],
tabCurrent: 0,
2025-07-22 09:39:42 +08:00
activeTab: "unread",
2025-07-04 16:04:01 +08:00
showDevModal: false,
2025-07-22 09:39:42 +08:00
defaultAvatar: "/static/avatar/default-avatar.png",
2025-07-04 16:04:01 +08:00
unreadMessages: [
{
id: 1,
2025-07-22 09:39:42 +08:00
avatar: "",
username: "浙江理工生13024",
time: "2023/6/26 15:45:12",
question: "学校在录取时有没有一些专业会有特殊要求?",
reply: "",
2025-07-04 16:04:01 +08:00
expanded: false,
2025-07-22 09:39:42 +08:00
show: false,
2025-07-04 16:04:01 +08:00
},
{
id: 2,
2025-07-22 09:39:42 +08:00
avatar: "",
username: "理工13024",
time: "2023/6/26 15:45:12",
question: "在录取时有没有一些专业会有特殊要求?",
reply: "",
2025-07-04 16:04:01 +08:00
expanded: false,
2025-07-22 09:39:42 +08:00
show: false,
},
2025-07-04 16:04:01 +08:00
],
repliedMessages: [
{
id: 3,
2025-07-22 09:39:42 +08:00
avatar: "",
username: "浙江理工生13024",
time: "2023/6/26 15:45:12",
question: "学校在录取时有没有一些专业会有特殊要求?",
reply:
"学生与体健康状况必须符合教育部、卫生部、中国残疾人联合会印发的《普通高等学校招生体检工作指导意见》和人力资源社会保障部、原卫生部、原教育部、原公安部、原国家人口计划生育委员会制定的有关规定。原卫生部、原教育部、原公安部、原国家人口计划生育委员会制定的有关规定。",
replyUser: "系统回复",
2025-07-04 16:04:01 +08:00
expanded: false,
2025-07-22 09:39:42 +08:00
show: false,
},
],
swipeOptions: [
{
2025-07-22 09:39:42 +08:00
text: "删除",
style: {
2025-07-22 09:39:42 +08:00
backgroundColor: "#fa3534",
color: "#ffffff",
fontSize: "15px",
},
},
],
2025-07-04 16:04:01 +08:00
};
},
computed: {
currentMessages() {
2025-07-22 09:39:42 +08:00
return this.activeTab === "unread"
? this.unreadMessages
: this.repliedMessages;
},
2025-07-04 16:04:01 +08:00
},
methods: {
onTabChange(index) {
this.tabCurrent = index;
// 根据索引设置activeTab值
2025-07-22 09:39:42 +08:00
this.activeTab = index === 0 ? "unread" : "replied";
// 切换选项卡时关闭所有打开的滑动按钮
this.closeAllSwipe();
},
2025-07-04 16:04:01 +08:00
switchTab(tab) {
this.activeTab = tab;
// 更新tabCurrent以匹配activeTab
2025-07-22 09:39:42 +08:00
this.tabCurrent = tab === "unread" ? 0 : 1;
2025-07-04 16:04:01 +08:00
// 切换选项卡时关闭所有打开的滑动按钮
this.closeAllSwipe();
},
handleTabChange(path, index) {
2025-07-22 09:39:42 +08:00
console.log("切换到标签页:", path, index);
2025-07-04 16:04:01 +08:00
},
handleReply(item) {
this.showDevModal = true;
},
toggleExpand(item) {
item.expanded = !item.expanded;
},
handleSwipeClick(e) {
2025-07-22 09:39:42 +08:00
const { index } = e; // 当前点击的滑动单元格索引
const btnIndex = e.index; // 点击的按钮索引
2025-07-22 09:39:42 +08:00
if (btnIndex === 0) {
// 删除按钮
// 删除当前消息
2025-07-22 09:39:42 +08:00
if (this.activeTab === "unread") {
this.unreadMessages.splice(index, 1);
} else {
this.repliedMessages.splice(index, 1);
}
2025-07-04 16:04:01 +08:00
}
},
handleSwipeOpen(e, index) {
2025-07-04 16:04:01 +08:00
// 打开滑动按钮时,关闭其他打开的滑动按钮
this.closeOther(index);
},
handleSwipeClose(e, index) {
// 处理滑动关闭事件
2025-07-22 09:39:42 +08:00
if (this.activeTab === "unread") {
this.unreadMessages[index].show = false;
} else {
this.repliedMessages[index].show = false;
}
},
2025-07-04 16:04:01 +08:00
closeOther(index) {
// 关闭除当前外的所有滑动按钮
2025-07-22 09:39:42 +08:00
if (this.activeTab === "unread") {
2025-07-04 16:04:01 +08:00
this.unreadMessages.forEach((item, idx) => {
if (idx !== index) {
item.show = false;
}
});
} else {
this.repliedMessages.forEach((item, idx) => {
if (idx !== index) {
item.show = false;
}
});
}
},
closeAllSwipe() {
// 关闭所有滑动按钮
2025-07-22 09:39:42 +08:00
this.unreadMessages.forEach((item) => {
2025-07-04 16:04:01 +08:00
item.show = false;
});
2025-07-22 09:39:42 +08:00
this.repliedMessages.forEach((item) => {
2025-07-04 16:04:01 +08:00
item.show = false;
});
2025-07-22 09:39:42 +08:00
},
},
};
2025-07-04 16:04:01 +08:00
</script>
<style scoped>
.notes-page {
height: 100vh;
background-color: #f5f6fa;
display: flex;
flex-direction: column;
position: relative;
}
2025-07-22 09:39:42 +08:00
.custom-tabs-box {
display: flex;
align-items: center;
2025-07-04 16:04:01 +08:00
}
2025-07-22 09:39:42 +08:00
.space {
flex: 1;
background: #fff;
width: 100%;
height: 100%;
2025-07-04 16:04:01 +08:00
}
.custom-tabs-box >>> .u-tabs__wrapper__nav__item {
padding: 0 20px 0 0 !important; /* 调整标签项的padding */
}
.custom-tabs-box >>> .u-tabs__wrapper__nav__line {
bottom: 0 !important; /* 确保下划线位于底部 */
height: 4px !important; /* 设置下划线高度 */
border-radius: 2px !important; /* 圆角 */
2025-07-04 16:04:01 +08:00
}
.content-wrapper {
flex: 1;
display: flex;
flex-direction: column;
padding-bottom: 60px; /* 为底部导航栏预留空间 */
overflow-y: auto; /* 允许内容滚动 */
}
/* 留言列表样式 */
.message-list {
flex: 1;
padding: 10px;
}
.message-item {
background-color: #fff;
padding: 15px;
margin-bottom: 10px;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}
.message-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.user-info {
display: flex;
align-items: center;
}
.avatar {
width: 24px;
height: 24px;
border-radius: 50%;
margin-right: 8px;
background-color: #eee;
}
.username {
font-size: 12px;
color: #666;
}
.message-time {
font-size: 12px;
color: #999;
}
.message-content {
position: relative;
2025-07-04 16:04:01 +08:00
}
.question {
display: flex;
2025-07-04 16:04:01 +08:00
margin-bottom: 10px;
}
.question-icon {
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #4a6cf7;
color: #fff;
font-size: 12px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 8px;
flex-shrink: 0;
}
.question-text {
font-size: 14px;
line-height: 1.5;
flex: 1;
}
.reply-button {
height: 32px;
background-color: #f0f2fd;
color: #4a6cf7;
border-radius: 4px;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
margin-top: 10px;
cursor: pointer;
}
.reply-button text {
margin-left: 5px;
}
.reply-content {
background-color: #f8f8f8;
border-radius: 4px;
padding: 10px;
margin-top: 10px;
}
.reply-header {
display: flex;
align-items: center;
margin-bottom: 5px;
}
.reply-icon {
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #ff9500;
color: #fff;
font-size: 12px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 8px;
}
.reply-info {
font-size: 12px;
color: #666;
}
.reply-text {
font-size: 14px;
line-height: 1.5;
color: #333;
margin-left: 28px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
.reply-text.expanded {
-webkit-line-clamp: unset;
}
.expand-button {
text-align: right;
font-size: 12px;
color: #4a6cf7;
margin-top: 5px;
cursor: pointer;
}
2025-07-04 16:04:01 +08:00
.empty-tip {
text-align: center;
padding: 20px;
color: #999;
font-size: 14px;
}
2025-07-22 09:39:42 +08:00
</style>