22
This commit is contained in:
@@ -87,6 +87,14 @@
|
|||||||
<artifactId>json</artifactId>
|
<artifactId>json</artifactId>
|
||||||
<version>20231013</version>
|
<version>20231013</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.ruoyi</groupId>
|
||||||
|
<artifactId>ruoyi-system</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.ruoyi.redis;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class RedisMessagePublisher {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private StringRedisTemplate redisTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向指定频道发布消息
|
||||||
|
* @param channel 频道名称
|
||||||
|
* @param message 消息内容(JSON字符串)
|
||||||
|
*/
|
||||||
|
public void publish(String channel, String message) {
|
||||||
|
redisTemplate.convertAndSend(channel, message);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 作用:发布消息到 Redis 频道:将 message 发送到指定的 channel。
|
||||||
|
* 触发订阅者处理:所有通过 RedisMessageListenerContainer 订阅了该频道的客户端(如其他微服务、后台任务等)会立即收到消息,并调用对应的消息处理器(如 onMessage 方法)。
|
||||||
|
*
|
||||||
|
* channel:目标频道名称(如 "game_room_channel")。
|
||||||
|
* message:要发送的消息,可以是任意对象(Spring 会自动序列化为字节数组或 JSON)。
|
||||||
|
*/
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.ruoyi.redis;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.socket.TextMessage;
|
||||||
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
import com.ruoyi.websocket.server.GameRoomWebSocketHandler;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class RedisMessageSubscriber {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ObjectMapper objectMapper;//是jackson里面的方法,主要处理序列化和反序列化
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理从Redis订阅到的消息
|
||||||
|
*/
|
||||||
|
public void onMessage(String redisMessage, String channel) {
|
||||||
|
try {
|
||||||
|
// 解析消息,其中应包含房间ID和要发送的实际消息体
|
||||||
|
Map<String, Object> messageMap = objectMapper.readValue(redisMessage, Map.class);
|
||||||
|
String targetRoomId = (String) messageMap.get("roomId");
|
||||||
|
Map<String, Object> actualMessageToSend = (Map<String, Object>) messageMap.get("message");
|
||||||
|
|
||||||
|
// 调用本地广播方法,只发送给本实例内指定房间的用户
|
||||||
|
broadcastToLocalRoom(targetRoomId, actualMessageToSend);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("处理Redis消息失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅向本地会话(即当前JVM内的WebSocketSession)广播消息
|
||||||
|
*/
|
||||||
|
private void broadcastToLocalRoom(String roomId, Map<String, Object> message) throws Exception {
|
||||||
|
// 遍历原Handler中的sessions变量(需稍作调整使其可被访问)
|
||||||
|
for (Map.Entry<String, WebSocketSession> entry : GameRoomWebSocketHandler.getSessions().entrySet()) {
|
||||||
|
String sessionKey = entry.getKey();
|
||||||
|
if (sessionKey.startsWith(roomId + "_")) { // 判断是否属于目标房间
|
||||||
|
WebSocketSession session = entry.getValue();
|
||||||
|
if (session != null && session.isOpen()) {
|
||||||
|
try {
|
||||||
|
String jsonMessage = objectMapper.writeValueAsString(message);
|
||||||
|
session.sendMessage(new TextMessage(jsonMessage));
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("向本地会话发送消息失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package com.ruoyi.redis;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.listener.ChannelTopic;
|
||||||
|
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||||
|
import org.springframework.data.redis.listener.Topic;
|
||||||
|
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class RedisPubSubConfig {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisConnectionFactory redisConnectionFactory;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisMessageSubscriber redisMessageSubscriber;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RedisMessageListenerContainer redisMessageListenerContainer() {
|
||||||
|
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||||
|
container.setConnectionFactory(redisConnectionFactory);// 设置 Redis 连接
|
||||||
|
|
||||||
|
// 订阅游戏房间频道
|
||||||
|
Topic gameRoomTopic = new ChannelTopic("game_room_channel"); // 订阅的频道
|
||||||
|
// 指定消息处理器(即redisMessageSubscriber的onMessage方法)
|
||||||
|
container.addMessageListener(new MessageListenerAdapter(redisMessageSubscriber, "onMessage"), gameRoomTopic);// addMessageListener绑定监听器和频道
|
||||||
|
/**
|
||||||
|
* 整工作流程
|
||||||
|
* 启动应用:Spring 初始化 RedisMessageListenerContainer,并建立与 Redis 的连接。
|
||||||
|
* 订阅频道:容器开始监听 game_room_channel 频道。
|
||||||
|
* 发布消息:其他服务或代码通过 Redis 的 PUBLISH 命令向 game_room_channel 发送消息,例如:
|
||||||
|
* bash
|
||||||
|
* PUBLISH game_room_channel "Hello, Game Room!"
|
||||||
|
* 消息处理:
|
||||||
|
* Redis 将消息推送给所有订阅者。
|
||||||
|
* RedisMessageListenerContainer 接收到消息后,调用 RedisMessageSubscriber.onMessage() 方法。
|
||||||
|
* 消息内容作为参数传递给 onMessage 方法,由开发者自定义处理逻辑(如更新游戏状态、广播通知等)。
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* MessageListenerAdapter
|
||||||
|
* 作用:将 Redis 消息转发到指定的处理器方法(这里是 redisMessageSubscriber.onMessage)。
|
||||||
|
* 关键点:
|
||||||
|
* 第二个参数 "onMessage" 指定处理器方法名(需在 RedisMessageSubscriber 中实现)。
|
||||||
|
* 默认情况下,消息会以 byte[] 形式传递给处理器,Spring 会自动反序列化。
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 发布消息的步骤
|
||||||
|
* 选择消息中间件:根据需求(如吞吐量、持久性、延迟)选择合适的工具。
|
||||||
|
* 创建主题(Topic)或队列(Queue):
|
||||||
|
* 主题(Topic):一对多广播(所有订阅者都能收到消息)。
|
||||||
|
* 队列(Queue):点对点(消息被一个订阅者消费)。
|
||||||
|
* 发布消息:
|
||||||
|
* 指定主题/队列名称。
|
||||||
|
* 发送消息内容(通常是JSON、Protobuf等格式)。
|
||||||
|
*/
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,32 @@
|
|||||||
package com.ruoyi.websocket.server;
|
package com.ruoyi.websocket.server;
|
||||||
|
|
||||||
|
import com.ruoyi.system.domain.ScoreRoomDetail;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.web.socket.*;
|
import org.springframework.web.socket.*;
|
||||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class GameRoomWebSocketHandler extends TextWebSocketHandler {
|
public class GameRoomWebSocketHandler extends TextWebSocketHandler {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private StringRedisTemplate redisTemplate;
|
||||||
// 存储所有连接的会话
|
// 存储所有连接的会话
|
||||||
private static final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
|
private static final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
|
||||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
public static Map<String, WebSocketSession> getSessions() {
|
||||||
|
return Collections.unmodifiableMap(sessions); // 返回不可修改的视图,保证线程安全
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||||
// 1. 从路径参数中获取 roomId 和 userId
|
// 1. 从路径参数中获取 roomId 和 userId
|
||||||
@@ -40,9 +53,12 @@ public class GameRoomWebSocketHandler extends TextWebSocketHandler {
|
|||||||
welcomeMsg.put("message", "欢迎加入房间: " + roomId);
|
welcomeMsg.put("message", "欢迎加入房间: " + roomId);
|
||||||
welcomeMsg.put("roomId", roomId);
|
welcomeMsg.put("roomId", roomId);
|
||||||
welcomeMsg.put("userId", userId);
|
welcomeMsg.put("userId", userId);
|
||||||
|
|
||||||
welcomeMsg.put("timestamp", System.currentTimeMillis());
|
welcomeMsg.put("timestamp", System.currentTimeMillis());
|
||||||
|
|
||||||
sendJsonMessage(session, welcomeMsg);
|
sendJsonMessage(session, welcomeMsg);
|
||||||
|
|
||||||
|
broadcastJsonToRoom(roomId,welcomeMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -64,22 +80,42 @@ public class GameRoomWebSocketHandler extends TextWebSocketHandler {
|
|||||||
try {
|
try {
|
||||||
// 解析客户端发送的 JSON 消息
|
// 解析客户端发送的 JSON 消息
|
||||||
Map<String, Object> clientMessage = objectMapper.readValue(payload, Map.class);
|
Map<String, Object> clientMessage = objectMapper.readValue(payload, Map.class);
|
||||||
String msgType = (String) clientMessage.getOrDefault("type", "chat");
|
String msgType = (String) clientMessage.getOrDefault("type", "system");
|
||||||
|
System.out.println("消息类型" + msgType);
|
||||||
|
if(msgType.equals("scoreUpdate")){
|
||||||
|
int Score = (int) clientMessage.get("Score");
|
||||||
|
int giveUserScore = (int) clientMessage.get("giveUserScore") - Score;
|
||||||
|
int givedUserScore = (int) clientMessage.get("givedUserScore") + Score;
|
||||||
|
Map<String, Object> scoreUpdateMsg = new HashMap<>();
|
||||||
|
scoreUpdateMsg.put("type", msgType);
|
||||||
|
scoreUpdateMsg.put("giveUserId",clientMessage.get("giveUserId"));
|
||||||
|
scoreUpdateMsg.put("giveUserScore",giveUserScore);
|
||||||
|
scoreUpdateMsg.put("givedUserId",clientMessage.get("givedUserId"));
|
||||||
|
scoreUpdateMsg.put("givedUserScore",givedUserScore);
|
||||||
|
broadcastJsonToRoom(roomId,scoreUpdateMsg);
|
||||||
|
}else if(msgType.equals("scoreUpdates")){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
else if(msgType.equals("userJoined")){
|
||||||
|
|
||||||
Map<String, Object> broadcastMsg = new HashMap<>();
|
Map<String, Object> broadcastMsg = new HashMap<>();
|
||||||
broadcastMsg.put("type", msgType);
|
broadcastMsg.put("type", msgType);
|
||||||
broadcastMsg.put("userId", userId);
|
broadcastMsg.put("userId", userId);
|
||||||
broadcastMsg.put("roomId", roomId);
|
broadcastMsg.put("roomId", roomId);
|
||||||
broadcastMsg.put("content", clientMessage.get("content"));
|
broadcastMsg.put("nickName", clientMessage.get("nickName"));
|
||||||
|
broadcastMsg.put("avatars", clientMessage.get("avatars"));
|
||||||
broadcastMsg.put("timestamp", System.currentTimeMillis());
|
broadcastMsg.put("timestamp", System.currentTimeMillis());
|
||||||
|
|
||||||
broadcastJsonToRoom(roomId, broadcastMsg);
|
broadcastJsonToRoom(roomId, broadcastMsg);
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println("解析客户端消息失败,按文本处理: " + e.getMessage());
|
System.out.println("解析客户端消息失败,按文本处理: " + e.getMessage());
|
||||||
|
|
||||||
Map<String, Object> broadcastMsg = new HashMap<>();
|
Map<String, Object> broadcastMsg = new HashMap<>();
|
||||||
broadcastMsg.put("type", "chat");
|
broadcastMsg.put("type", "error");
|
||||||
broadcastMsg.put("userId", userId);
|
broadcastMsg.put("userId", userId);
|
||||||
broadcastMsg.put("roomId", roomId);
|
broadcastMsg.put("roomId", roomId);
|
||||||
broadcastMsg.put("content", payload);
|
broadcastMsg.put("content", payload);
|
||||||
@@ -151,12 +187,14 @@ public class GameRoomWebSocketHandler extends TextWebSocketHandler {
|
|||||||
|
|
||||||
// 辅助方法:广播 JSON 消息到指定房间
|
// 辅助方法:广播 JSON 消息到指定房间
|
||||||
private void broadcastJsonToRoom(String roomId, Map<String, Object> message) throws Exception {
|
private void broadcastJsonToRoom(String roomId, Map<String, Object> message) throws Exception {
|
||||||
String jsonMessage = objectMapper.writeValueAsString(message);
|
|
||||||
for (Map.Entry<String, WebSocketSession> entry : sessions.entrySet()) {
|
for (Map.Entry<String, WebSocketSession> entry : sessions.entrySet()) {
|
||||||
if (entry.getKey().startsWith(roomId + "_")) {
|
if (entry.getKey().startsWith(roomId + "_")) {
|
||||||
WebSocketSession session = entry.getValue();
|
WebSocketSession session = entry.getValue();
|
||||||
if (session.isOpen()) {
|
if (session.isOpen()) {
|
||||||
session.sendMessage(new TextMessage(jsonMessage));
|
System.out.println(message);
|
||||||
|
sendJsonMessage(session, message);
|
||||||
|
System.out.println(111);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,5 +13,5 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/*每个页面公共css */
|
|
||||||
</style>
|
</style>
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
import App from './App'
|
import App from './App'
|
||||||
import { getToken,checkLoginStatus } from '@/api/login.js';
|
import {
|
||||||
|
getToken,
|
||||||
|
checkLoginStatus
|
||||||
|
} from '@/api/login.js';
|
||||||
import StaticValue from '@/utils/StaticValue.js'
|
import StaticValue from '@/utils/StaticValue.js'
|
||||||
|
|
||||||
// #ifndef VUE3
|
// #ifndef VUE3
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import './uni.promisify.adaptor'
|
import './uni.promisify.adaptor'
|
||||||
|
import uView from 'uview-ui'; // 如果 uView 支持模块化导出
|
||||||
|
Vue.use(uView)
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
App.mpType = 'app'
|
App.mpType = 'app'
|
||||||
const app = new Vue({
|
const app = new Vue({
|
||||||
@@ -14,7 +19,9 @@ app.$mount()
|
|||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// #ifdef VUE3
|
// #ifdef VUE3
|
||||||
import { createSSRApp } from 'vue'
|
import {
|
||||||
|
createSSRApp
|
||||||
|
} from 'vue'
|
||||||
export function createApp() {
|
export function createApp() {
|
||||||
const app = createSSRApp(App)
|
const app = createSSRApp(App)
|
||||||
app.config.globalProperties.$StaticValue = StaticValue; // 挂载全局变量
|
app.config.globalProperties.$StaticValue = StaticValue; // 挂载全局变量
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"less": "^4.4.2",
|
"less": "^4.4.2",
|
||||||
"less-loader": "^12.3.0"
|
"less-loader": "^12.3.0",
|
||||||
|
"uview-ui": "^2.0.38",
|
||||||
|
"vue": "^3.5.24"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^6.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,4 +59,6 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"uniIdRouter": {}
|
"uniIdRouter": {}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|
||||||
<!-- 未结束对局提示 -->
|
<!-- 未结束对局提示 -->
|
||||||
<view class="notice">
|
<view class="notice">
|
||||||
<view class="notice-icon">
|
<view class="notice-icon">
|
||||||
|
|||||||
@@ -7,23 +7,12 @@
|
|||||||
<!-- 功能菜单 -->
|
<!-- 功能菜单 -->
|
||||||
<view class="header">
|
<view class="header">
|
||||||
<view class="list-container">
|
<view class="list-container">
|
||||||
<view class="list-item">
|
<view class="list-item"><text @click="changeA">+ </text>
|
||||||
<text class="number">1</text>
|
<text>添加玩家</text>
|
||||||
<text class="text">添加玩家</text>
|
|
||||||
</view>
|
|
||||||
<view class="list-item">
|
|
||||||
<text class="number">2</text>
|
|
||||||
<text class="text">转让房主</text>
|
|
||||||
</view>
|
|
||||||
<view class="list-item">
|
|
||||||
<text class="number">3</text>
|
|
||||||
<text class="text">语音播报</text>
|
|
||||||
<text class="voice-status">{{}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="list-item">
|
|
||||||
<text class="number">4</text>
|
|
||||||
<text class="text">台板(茶水)</text>
|
|
||||||
</view>
|
</view>
|
||||||
|
<view class="list-item"><text @click="changeA">♟</text> <text>转让计分员</text></view>
|
||||||
|
<view class="list-item"><text @click="changeX">{{X}}</text> <text>语音播报</text></view>
|
||||||
|
<view class="list-item"><text @click="changeY">{{Y}}</text> <text>台板</text></view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -62,7 +51,7 @@
|
|||||||
{{item.score}}
|
{{item.score}}
|
||||||
</text>
|
</text>
|
||||||
<view class="player-action">
|
<view class="player-action">
|
||||||
<button class="btn-batch" @click="giveScore">给分</button>
|
<button class="btn-batch" @click="giveScore(item)">给分</button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -79,7 +68,7 @@
|
|||||||
<!-- 底部操作栏 -->
|
<!-- 底部操作栏 -->
|
||||||
<view class="footer">
|
<view class="footer">
|
||||||
<button class="btn-detail">给分详情</button>
|
<button class="btn-detail">给分详情</button>
|
||||||
<button class="btn-settle">结算房间</button>
|
<button class="btn-settle" @click="endRoom">结算房间</button>
|
||||||
</view>
|
</view>
|
||||||
<div class="give-score" v-if="IsGive">
|
<div class="give-score" v-if="IsGive">
|
||||||
<div class="give-contain">
|
<div class="give-contain">
|
||||||
@@ -92,7 +81,7 @@
|
|||||||
<!-- 按钮区域 -->
|
<!-- 按钮区域 -->
|
||||||
<div class="give-footer">
|
<div class="give-footer">
|
||||||
<button class="btn btn-cancel" @click="closeGive">取消</button>
|
<button class="btn btn-cancel" @click="closeGive">取消</button>
|
||||||
<button class="btn btn-confirm">确定</button>
|
<button class="btn btn-confirm" @click="confirmGive">确定</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -103,12 +92,19 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import {
|
||||||
ref,
|
ref,
|
||||||
onUnmounted
|
onMounted,
|
||||||
|
onUnmounted,
|
||||||
|
getCurrentInstance
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import {
|
import {
|
||||||
onLoad
|
onLoad
|
||||||
} from '@dcloudio/uni-app'
|
} from '@dcloudio/uni-app'
|
||||||
|
const proxy = getCurrentInstance().proxy;
|
||||||
|
const userInfo = ref({})
|
||||||
|
const getUserInfo = async () => {
|
||||||
|
userInfo.value = proxy.$StaticValue.getUserInfo();
|
||||||
|
}
|
||||||
|
const GiveScoreData = ref({}) //给分更新分数的对象
|
||||||
const isSelf = ref(true)
|
const isSelf = ref(true)
|
||||||
const voiceEnabled = ref(true)
|
const voiceEnabled = ref(true)
|
||||||
const socketTask = ref(null) // 改为使用 uni-app 的 SocketTask
|
const socketTask = ref(null) // 改为使用 uni-app 的 SocketTask
|
||||||
@@ -116,8 +112,49 @@
|
|||||||
const roomUsers = ref([])
|
const roomUsers = ref([])
|
||||||
const Score = ref(0)
|
const Score = ref(0)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
头上那一点
|
||||||
|
|
||||||
|
*/
|
||||||
|
const X = ref('关')
|
||||||
|
const Y = ref('关')
|
||||||
|
|
||||||
|
function changeX() {
|
||||||
|
if (X.value == '关') {
|
||||||
|
X.value = '开'
|
||||||
|
} else {
|
||||||
|
X.value = '关'
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeY() {
|
||||||
|
if (Y.value == '关') {
|
||||||
|
Y.value = '开'
|
||||||
|
} else {
|
||||||
|
Y.value = '关'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeA() {
|
||||||
|
|
||||||
|
uni.showToast({
|
||||||
|
title: '入机房间不需要',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function endRoom() {
|
||||||
|
uni.showToast({
|
||||||
|
title: '计算成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
console.log("556", options.roomUserInfo)
|
console.log("556", options.roomUserInfo)
|
||||||
|
|
||||||
let roomUserInfo = null;
|
let roomUserInfo = null;
|
||||||
|
|
||||||
if (options.roomUserInfo) {
|
if (options.roomUserInfo) {
|
||||||
@@ -126,32 +163,8 @@
|
|||||||
roomUserInfo = JSON.parse(decodedInfo);
|
roomUserInfo = JSON.parse(decodedInfo);
|
||||||
console.log('解析后的数据:', roomUserInfo);
|
console.log('解析后的数据:', roomUserInfo);
|
||||||
|
|
||||||
if (roomUserInfo?.playerType === 'business') {
|
|
||||||
const userId = roomUserInfo.createUser;
|
console.log("用户加入的用户信息初始化", roomUserInfo)
|
||||||
const exists = roomUsers.value.some(user => user.userId === userId);
|
|
||||||
if (!exists) {
|
|
||||||
roomUsers.value.push({
|
|
||||||
userId: userId,
|
|
||||||
score: 0,
|
|
||||||
playerType: 'business',
|
|
||||||
nickName: roomUserInfo.nickName,
|
|
||||||
avatars: roomUserInfo.avatars
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (roomUserInfo?.playerType === 'user') {
|
|
||||||
const userId = roomUserInfo.createUser;
|
|
||||||
const exists = roomUsers.value.some(user => user.userId === userId);
|
|
||||||
if (!exists) {
|
|
||||||
roomUsers.value.push({
|
|
||||||
userId: userId,
|
|
||||||
score: 0,
|
|
||||||
playerType: 'user',
|
|
||||||
nickName: roomUserInfo.nickName,
|
|
||||||
avatars: roomUserInfo.avatars
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log("888888888888", roomUserInfo)
|
|
||||||
// 初始化WebSocket连接
|
// 初始化WebSocket连接
|
||||||
initWebSocket(roomUserInfo);
|
initWebSocket(roomUserInfo);
|
||||||
}
|
}
|
||||||
@@ -217,15 +230,14 @@
|
|||||||
const sendJoinRoomMessage = (roomUserInfo) => {
|
const sendJoinRoomMessage = (roomUserInfo) => {
|
||||||
if (socketTask.value) {
|
if (socketTask.value) {
|
||||||
const joinMsg = {
|
const joinMsg = {
|
||||||
type: 'join_room',
|
type: 'userJoined',
|
||||||
roomId: roomUserInfo.roomId,
|
roomId: roomUserInfo.roomId,
|
||||||
userId: roomUserInfo.userId,
|
userId: roomUserInfo.userId,
|
||||||
userInfo: {
|
|
||||||
nickName: roomUserInfo.nickName,
|
nickName: roomUserInfo.nickName,
|
||||||
avatars: roomUserInfo.avatars // 修正拼写错误
|
avatars: roomUserInfo.avatars
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
};
|
||||||
|
console.log("发送加入消息", joinMsg)
|
||||||
// 使用 SocketTask 的 send 方法
|
// 使用 SocketTask 的 send 方法
|
||||||
socketTask.value.send({
|
socketTask.value.send({
|
||||||
data: JSON.stringify(joinMsg),
|
data: JSON.stringify(joinMsg),
|
||||||
@@ -242,16 +254,24 @@
|
|||||||
// 处理WebSocket消息(保持不变)
|
// 处理WebSocket消息(保持不变)
|
||||||
const handleWebSocketMessage = (message) => {
|
const handleWebSocketMessage = (message) => {
|
||||||
console.log('收到消息:', message);
|
console.log('收到消息:', message);
|
||||||
|
console.log('收到消息:', message.type);
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case 'user_joined':
|
case 'system':
|
||||||
handlePlayerJoin(message.data);
|
console.log("系统消息", roomUsers.value)
|
||||||
break;
|
break;
|
||||||
case 'user_left':
|
case 'userJoined':
|
||||||
|
console.log("用户加入消息", message.userId)
|
||||||
|
handlePlayerJoin(message);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'scoreUpdate':
|
||||||
|
handleScoreUpdate(message);
|
||||||
|
break;
|
||||||
|
case 'userLeft':
|
||||||
handlePlayerLeave(message.data);
|
handlePlayerLeave(message.data);
|
||||||
break;
|
break;
|
||||||
case 'score_update':
|
case 'error':
|
||||||
handleScoreUpdate(message.data);
|
console.log("发生错误77777777777777777777777")
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.log('未知消息类型:', message);
|
console.log('未知消息类型:', message);
|
||||||
@@ -260,15 +280,17 @@
|
|||||||
|
|
||||||
// 处理玩家加入(保持不变)
|
// 处理玩家加入(保持不变)
|
||||||
const handlePlayerJoin = (playerData) => {
|
const handlePlayerJoin = (playerData) => {
|
||||||
|
console.log("玩家加入的名称", playerData.nickName)
|
||||||
const exists = roomUsers.value.some(user => user.userId === playerData.userId);
|
const exists = roomUsers.value.some(user => user.userId === playerData.userId);
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
roomUsers.value.push({
|
roomUsers.value.push({
|
||||||
userId: playerData.userId,
|
userId: +playerData.userId,
|
||||||
score: 0,
|
score: 0,
|
||||||
playerType: playerData.playerType || 'user',
|
playerType: playerData.playerType || 'user',
|
||||||
nickName: playerData.nickName,
|
nickName: playerData.nickName,
|
||||||
avatars: playerData.avatars
|
avatars: playerData.avatars || ''
|
||||||
});
|
});
|
||||||
|
console.log("加入处理后的房间人数信息", roomUsers.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,39 +301,54 @@
|
|||||||
|
|
||||||
// 处理分数更新(保持不变)
|
// 处理分数更新(保持不变)
|
||||||
const handleScoreUpdate = (scoreData) => {
|
const handleScoreUpdate = (scoreData) => {
|
||||||
const user = roomUsers.value.find(user => user.userId === scoreData.userId);
|
console.log("更新分数的数据", scoreData)
|
||||||
if (user) {
|
const giveId = scoreData.giveUserId
|
||||||
user.score = scoreData.newScore;
|
const givedId = scoreData.givedUserId
|
||||||
}
|
roomUsers.value.find(i => i.userId == giveId).score = scoreData.giveUserScore
|
||||||
|
roomUsers.value.find(i => i.userId == givedId).score = scoreData.givedUserScore
|
||||||
|
|
||||||
|
console.log("更新完后的数据", roomUsers.value)
|
||||||
}
|
}
|
||||||
//给分
|
//给分
|
||||||
const giveScore = () => {
|
const giveScore = (data) => {
|
||||||
IsGive.value = true
|
IsGive.value = true
|
||||||
|
GiveScoreData.value = data
|
||||||
}
|
}
|
||||||
//取消给分
|
//取消给分
|
||||||
const closeGive = () => {
|
const closeGive = () => {
|
||||||
|
Score.value = 0
|
||||||
IsGive.value = false
|
IsGive.value = false
|
||||||
}
|
}
|
||||||
//确认给分
|
//确认给分
|
||||||
const confirmGive = () => {
|
const confirmGive = () => {
|
||||||
|
const item = GiveScoreData.value
|
||||||
|
console.log("给分的对象", item)
|
||||||
|
console.log("roomUsers的数据", roomUsers.value)
|
||||||
|
const self = roomUsers.value.find(i => i.userId == userInfo.value.userId)
|
||||||
|
const selfScore = self.score
|
||||||
|
console.log("自己的分数", selfScore)
|
||||||
|
const changeScore = {
|
||||||
|
type: 'scoreUpdate',
|
||||||
|
giveUserId: userInfo.value.userId,
|
||||||
|
giveUserScore: selfScore,
|
||||||
|
givedUserId: item.userId,
|
||||||
|
givedUserScore: item.score,
|
||||||
|
Score: +Score.value
|
||||||
|
}
|
||||||
|
console.log("给出的分数详情", changeScore)
|
||||||
|
socketTask.value.send({
|
||||||
|
data: JSON.stringify(changeScore),
|
||||||
|
success: () => {
|
||||||
|
console.log("给分成功")
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
console.log("给分失败")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Score.value = 0
|
||||||
IsGive.value = false
|
IsGive.value = false
|
||||||
}
|
}
|
||||||
// 发送WebSocket消息 - 适配 SocketTask API
|
|
||||||
const sendWebSocketMessage = (message) => {
|
|
||||||
if (socketTask.value) {
|
|
||||||
socketTask.value.send({
|
|
||||||
data: JSON.stringify(message),
|
|
||||||
success: () => {
|
|
||||||
console.log('消息发送成功');
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
console.error('消息发送失败:', err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.error('WebSocket未连接,无法发送消息');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭WebSocket连接 - 适配 SocketTask API
|
// 关闭WebSocket连接 - 适配 SocketTask API
|
||||||
const closeWebSocket = () => {
|
const closeWebSocket = () => {
|
||||||
@@ -328,6 +365,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getUserInfo()
|
||||||
|
})
|
||||||
// 页面卸载时关闭连接
|
// 页面卸载时关闭连接
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
closeWebSocket();
|
closeWebSocket();
|
||||||
@@ -374,7 +414,7 @@
|
|||||||
|
|
||||||
.list-item {
|
.list-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 15rpx;
|
gap: 15rpx;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="single">
|
<view class="single">
|
||||||
<view class="header">
|
<view class="header">
|
||||||
|
|
||||||
|
|
||||||
<view class="list-container">
|
<view class="list-container">
|
||||||
<view class="list-item"><text>1</text> <text>添加玩家</text></view>
|
<view class="list-item"><text @click="changeA">+ </text>
|
||||||
<view class="list-item"><text>2</text> <text>转让计分员</text></view>
|
<text>添加玩家</text>
|
||||||
<view class="list-item"><text>3</text> <text>语音播报</text></view>
|
</view>
|
||||||
<view class="list-item"><text>4</text> <text>台板</text></view>
|
<view class="list-item"><text @click="changeA">♟</text> <text>转让计分员</text></view>
|
||||||
|
<view class="list-item"><text @click="changeX">{{X}}</text> <text>语音播报</text></view>
|
||||||
|
<view class="list-item"><text @click="changeY">{{Y}}</text> <text>台板</text></view>
|
||||||
</view>
|
</view>
|
||||||
<view class="remind">
|
<view class="remind">
|
||||||
<text class="remind-title">对局记录</text><text class="remind-content">点击对局进行修改</text>
|
<text class="remind-title">对局记录</text><text class="remind-content">点击对局进行修改</text>
|
||||||
@@ -58,8 +62,8 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="footer">
|
<view class="footer">
|
||||||
<view class="start btn-primary">开局计分</view>
|
<view class="start btn-primary" @click="startRoom">开局计分</view>
|
||||||
<view class="end btn-secondary">结算房间</view>
|
<view class="end btn-secondary" @click="endRoom">结算房间</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -87,6 +91,48 @@
|
|||||||
scores: [3, 4, -3, 2]
|
scores: [3, 4, -3, 2]
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
const X = ref('关')
|
||||||
|
const Y = ref('关')
|
||||||
|
|
||||||
|
function changeX() {
|
||||||
|
if (X.value == '关') {
|
||||||
|
X.value = '开'
|
||||||
|
} else {
|
||||||
|
X.value = '关'
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeY() {
|
||||||
|
if (Y.value == '关') {
|
||||||
|
Y.value = '开'
|
||||||
|
} else {
|
||||||
|
Y.value = '关'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeA() {
|
||||||
|
|
||||||
|
uni.showToast({
|
||||||
|
title: '入机房间不需要',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function endRoom() {
|
||||||
|
uni.showToast({
|
||||||
|
title: '结算成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function startRoom() {
|
||||||
|
uni.showToast({
|
||||||
|
title: '已开始计分',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 对局数据
|
// 对局数据
|
||||||
const rounds = ref([1, 2, 3, 4]) // 4局
|
const rounds = ref([1, 2, 3, 4]) // 4局
|
||||||
@@ -133,7 +179,7 @@
|
|||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #666;
|
color: #666;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10rpx;
|
gap: 10rpx;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user