373 lines
8.2 KiB
Vue
373 lines
8.2 KiB
Vue
<script setup>
|
|
|
|
import Message from "./Message.vue";
|
|
import {onBeforeUnmount, onMounted, ref, watch} from "vue";
|
|
import api from "../../../utils/axios.js";
|
|
import store from "../../../store/index.js";
|
|
import swal from "../../../utils/sweetalert.js";
|
|
import AuthService from "../../../../services/auth.js";
|
|
import PagingController from "../../../components/PagingController.vue";
|
|
|
|
const messages = ref(store.state.demosLocal.board?.messages || []);
|
|
const amount = ref(store.state.demosLocal.board?.amount || 0);
|
|
const currentPage = ref(store.state.demosLocal.board?.currentPage || 1);
|
|
|
|
const pageLoading = ref(false);
|
|
const sendCD = ref(0);
|
|
|
|
const userInput = ref('');
|
|
let timer = null;
|
|
|
|
async function refreshBoard(page, pageSize) {
|
|
if (!page) {
|
|
page = currentPage.value;
|
|
}
|
|
if (!pageSize) {
|
|
pageSize = 10;
|
|
}
|
|
try {
|
|
await api.post(`/viewboard`, {
|
|
PAGE: page,
|
|
PAGE_SIZE: pageSize
|
|
}).then(res => {
|
|
res.data = res.data.map((msg)=>{
|
|
function stringToFloat(str) {
|
|
// 使用字符串的字符码生成一个基于字符串的唯一数值
|
|
let hash = 0;
|
|
for (let i = 0; i < str.length; i++) {
|
|
hash = (hash << 5) - hash + str.charCodeAt(i); // 位运算来生成哈希
|
|
hash = hash & hash; // 强制转换为32位整数
|
|
}
|
|
|
|
// 将哈希值映射到0~1之间
|
|
return Math.abs(hash) / (Math.pow(2, 32) - 1);
|
|
}
|
|
msg.likes = Math.round(stringToFloat('random'+ msg.content)*10000);
|
|
return msg;})
|
|
messages.value = res.data;
|
|
amount.value = Math.ceil(res.amount / pageSize);
|
|
store.commit('setLocalDemoValue', {demo: 'board', value: {messages: messages.value}});
|
|
store.commit('setLocalDemoValue', {demo: 'board', value: {amount: amount.value}});
|
|
})
|
|
} catch {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
async function goPage(page) {
|
|
const messageTemp = messages.value
|
|
const pageTemp = currentPage.value;
|
|
pageLoading.value = true;
|
|
currentPage.value = page;
|
|
if (await refreshBoard(page) === 0) {
|
|
store.commit('setLocalDemoValue', {demo: 'board', value: {currentPage: page}});
|
|
pageLoading.value = false;
|
|
return;
|
|
}
|
|
swal.tip('error', '加载留言板失败...')
|
|
messages.value = messageTemp;
|
|
currentPage.value = pageTemp;
|
|
pageLoading.value = false;
|
|
}
|
|
|
|
async function sendMessage() {
|
|
if (sendCD.value !== 0) {
|
|
return;
|
|
}
|
|
if (userInput.value.trim().length === 0) {
|
|
swal.tip('info', '不得为空')
|
|
return;
|
|
}
|
|
sendCD.value = 'wait';
|
|
try {
|
|
const response = await api.post('/postmessage', {
|
|
TOKEN: AuthService.getToken(),
|
|
CONTENT: userInput.value
|
|
});
|
|
if (response.code !== 0) {
|
|
swal.tip('error', '发送失败');
|
|
return;
|
|
}
|
|
userInput.value = '';
|
|
sendCD.value = 5;
|
|
store.commit('setLocalDemoValue', {demo: 'board', value: { sendCD: sendCD.value }});
|
|
await refreshBoard();
|
|
return;
|
|
} catch {
|
|
swal.tip('error', '网络连接错误...');
|
|
}
|
|
sendCD.value = 0;
|
|
}
|
|
|
|
async function clickRefresh() {
|
|
pageLoading.value = true;
|
|
if (await refreshBoard() !== 0) {
|
|
swal.tip('error', '刷新失败');
|
|
}
|
|
pageLoading.value = false;
|
|
}
|
|
|
|
let interval = null; // 定时器引用
|
|
function startCountdown() {
|
|
if (interval) clearInterval(interval); // 避免重复创建定时器
|
|
|
|
interval = setInterval(() => {
|
|
if (sendCD.value > 0) {
|
|
sendCD.value--;
|
|
store.commit('setLocalDemoValue', {demo: 'board', value: { sendCD: sendCD.value }});
|
|
} else {
|
|
clearInterval(interval);
|
|
interval = null;
|
|
}
|
|
}, 1000);
|
|
}
|
|
|
|
// 监听 sendCD 变量
|
|
watch(sendCD, (newValue) => {
|
|
if (newValue > 0 && !interval) {
|
|
startCountdown();
|
|
}
|
|
});
|
|
|
|
onMounted(async () => {
|
|
await refreshBoard();
|
|
timer = setInterval(refreshBoard, 7000);
|
|
});
|
|
|
|
onBeforeUnmount(() => {
|
|
if (timer) {
|
|
clearInterval(timer);
|
|
timer = null; // ✅ 避免悬空定时器
|
|
}
|
|
});
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<div class="container">
|
|
<div class="board-body">
|
|
<div class="message-container" :class="{loading: pageLoading}">
|
|
<Message v-for="msg in messages" :message="msg" @refresh-board="refreshBoard"/>
|
|
<div v-if="messages?.length === 0">正在加载...</div>
|
|
</div>
|
|
<paging-controller :current-page="currentPage" :amount="amount" :go-page-func="goPage" :loading="pageLoading"/>
|
|
</div>
|
|
<div class="sender-container">
|
|
<div class="sender-tips">
|
|
<img :src="store.getters.profileImage" alt="Avatar">
|
|
<div class="text">
|
|
<div>{{ store.state.userInfo.username || '请先登录' }}</div>
|
|
<div>{{ '<' + store.getters.userRole + '>' }}</div>
|
|
</div>
|
|
<div class="refresh-btn">
|
|
<button @click="clickRefresh">刷新</button>
|
|
</div>
|
|
</div>
|
|
<div class="sender-input">
|
|
<input class="message-input" v-model="userInput" @keydown.enter="sendMessage" :disabled="!store.state.userInfo.uid">
|
|
<button class="send-button" @click="sendMessage" :disabled="sendCD !== 0 || !store.state.userInfo.uid">
|
|
{{ sendCD === 0 ? '发送' : sendCD === 'wait' ? '稍等' : `${sendCD} 秒` }}
|
|
</button>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.container {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-items: flex-start;
|
|
width: 100%;
|
|
height: calc(100vh - 130px);
|
|
overflow: auto;
|
|
}
|
|
|
|
.board-body {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20px;
|
|
width: calc(100% - 60px);
|
|
max-width: 1000px;
|
|
margin: 0 auto 120px;
|
|
height: auto;
|
|
padding: 20px;
|
|
border-radius: 15px;
|
|
background: rgba(128, 128, 128, 0.06);
|
|
border: cyan solid 1px;
|
|
}
|
|
|
|
.theme-light .board-body {
|
|
border: #b2b2b2 solid 1px;
|
|
}
|
|
|
|
.message-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
gap: 15px;
|
|
transition: opacity 0.2s ease;
|
|
}
|
|
|
|
.message-container.loading {
|
|
opacity: 0.4;
|
|
}
|
|
|
|
.paging-container {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.page-btn {
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: black;
|
|
//width: 25px;
|
|
height: 25px;
|
|
padding: 0 5px;
|
|
border-radius: 4px;
|
|
border: cyan solid 1px;
|
|
}
|
|
|
|
.theme-light .page-btn {
|
|
background-color: white;
|
|
border: #b2b2b2 solid 1px;
|
|
}
|
|
|
|
.page-btn.active {
|
|
background: cyan;
|
|
color: black;
|
|
}
|
|
|
|
.theme-light .page-btn.active {
|
|
background: #2a2a2a;
|
|
color: white;
|
|
}
|
|
|
|
.sender-container {
|
|
margin: 20px;
|
|
background-color: #212121;
|
|
border: cyan solid 1px;
|
|
border-radius: 10px;
|
|
position: fixed;
|
|
bottom: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 95%;
|
|
height: auto;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.theme-light .sender-container {
|
|
background-color: white;
|
|
border: #b2b2b2 solid 1px;
|
|
}
|
|
|
|
.sender-tips {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: flex-start;
|
|
align-items: center;
|
|
width: 100%;
|
|
}
|
|
|
|
.sender-tips img {
|
|
width: 50px;
|
|
height: 50px;
|
|
margin: 15px 15px 0;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.sender-tips .text {
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
}
|
|
|
|
.refresh-btn {
|
|
flex: 1;
|
|
margin-right: 15px;
|
|
display: flex;
|
|
flex-direction: row-reverse;
|
|
}
|
|
|
|
.refresh-btn button {
|
|
background-color: #4f4f4f;
|
|
color: cyan;
|
|
width: 50px;
|
|
height: 50px;
|
|
margin: 15px 0 0 15px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.theme-light .refresh-btn button {
|
|
background-color: white;
|
|
color: #1a1a1a;
|
|
border: #1a1a1a solid 1px;
|
|
}
|
|
|
|
.sender-input {
|
|
display: flex;
|
|
flex-direction: row;
|
|
width: 97%;
|
|
gap: 10px;
|
|
margin: 15px;
|
|
transition: all 0.5s ease;
|
|
}
|
|
|
|
/* 输入框样式 */
|
|
.message-input {
|
|
flex: 1;
|
|
padding: 10px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 5px;
|
|
font-size: 16px;
|
|
outline: none;
|
|
}
|
|
|
|
/* 发送按钮样式 */
|
|
.send-button {
|
|
background-color: #007bff;
|
|
color: white;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
border-radius: 5px;
|
|
font-size: 16px;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.theme-light .send-button {
|
|
color: #1a1a1a;
|
|
background-color: #ffb74d;
|
|
}
|
|
|
|
/* 鼠标悬停时的按钮样式 */
|
|
.send-button:hover {
|
|
background-color: #0056b3;
|
|
}
|
|
|
|
.theme-light .send-button:hover {
|
|
background-color: #ffb74d;
|
|
}
|
|
|
|
.send-button:active {
|
|
transform: scale(0.95);
|
|
}
|
|
|
|
.send-button:disabled {
|
|
background-color: #9d9d9d;
|
|
}
|
|
.theme-light .send-button:disabled {
|
|
background-color: #9d9d9d;
|
|
}
|
|
</style> |