moonsflyer 4 月之前
父节点
当前提交
31cde71187
共有 4 个文件被更改,包括 757 次插入2 次删除
  1. 210 2
      dspIM/s1.js
  2. 202 0
      phalapi/src/app/Api/Livepk.php
  3. 41 0
      phalapi/src/app/Model/Live.php
  4. 304 0
      三人PK功能说明.md

+ 210 - 2
dspIM/s1.js

@@ -227,7 +227,14 @@ io.on('connection', function(socket) {
                                     pkuid1='0',
                                     pkuid2='0',
                                     pktotal1='0',
-                                    pktotal2='0';
+                                    pktotal2='0',
+                                    ifthreepk='0',
+                                    threepk_uid1='0',
+                                    threepk_uid2='0',
+                                    threepk_uid3='0',
+                                    threepk_total1='0',
+                                    threepk_total2='0',
+                                    threepk_total3='0';
                                 
                                 //console.log('SendGift');
                                 //console.log(resObj);
@@ -239,12 +246,34 @@ io.on('connection', function(socket) {
                                     pktotal2=''+resObj['pktotal2'];
                                     //console.log('pk');
                                 }
+                                
+                                // 检查是否是三人PK礼物
+                                if(resObj['isthreepk']==1 ){
+                                    ifthreepk='1';
+                                    threepk_uid1=''+resObj['threepk_uid1'];
+                                    threepk_uid2=''+resObj['threepk_uid2'];
+                                    threepk_uid3=''+resObj['threepk_uid3'];
+                                    threepk_total1=''+resObj['threepk_total1'];
+                                    threepk_total2=''+resObj['threepk_total2'];
+                                    threepk_total3=''+resObj['threepk_total3'];
+                                    console.log('三人PK礼物');
+                                }
+                                
 								dataObj['msg'][0]['ifpk']=ifpk;
                                 dataObj['msg'][0]['pkuid1']=pkuid1;
                                 dataObj['msg'][0]['pkuid2']=pkuid2;
                                 dataObj['msg'][0]['pktotal1']=pktotal1;
                                 dataObj['msg'][0]['pktotal2']=pktotal2;
                                 dataObj['msg'][0]['roomnum']=socket.roomnum;
+                                
+                                // 三人PK相关字段
+                                dataObj['msg'][0]['ifthreepk']=ifthreepk;
+                                dataObj['msg'][0]['threepk_uid1']=threepk_uid1;
+                                dataObj['msg'][0]['threepk_uid2']=threepk_uid2;
+                                dataObj['msg'][0]['threepk_uid3']=threepk_uid3;
+                                dataObj['msg'][0]['threepk_total1']=threepk_total1;
+                                dataObj['msg'][0]['threepk_total2']=threepk_total2;
+                                dataObj['msg'][0]['threepk_total3']=threepk_total3;
 								
 								
 								console.log('---------礼物信息--------------------'+[JSON.stringify(dataObj)]);
@@ -253,9 +282,14 @@ io.on('connection', function(socket) {
                                 
 								io.sockets.in(socket.roomnum).emit('broadcastingListen',[JSON.stringify(dataObj)]);
 								if(pkuid2>0){
-
                                     io.sockets.in(pkuid2).emit('broadcastingListen',[JSON.stringify(dataObj)]);
                                 }
+                                
+                                // 如果是三人PK,通知第三个房间
+                                if(ifthreepk=='1' && threepk_uid3>0){
+                                    io.sockets.in(threepk_uid2).emit('broadcastingListen',[JSON.stringify(dataObj)]);
+                                    io.sockets.in(threepk_uid3).emit('broadcastingListen',[JSON.stringify(dataObj)]);
+                                }
                                   
 			    				clientRedis.del(gifToken);
 			    			}
@@ -575,6 +609,133 @@ io.on('connection', function(socket) {
 	                    break;
 			    	}
 					
+					case 'LiveThreePK':{//三人主播PK
+						console.log("----------------三人主播PK------------"+data_str);
+					
+                        if(socket.roomnum != socket.uid){
+                            //非主播不能操作
+                            return !1;
+                        }
+                        var uid=msg['uid'];
+                        var pkuid2=msg['pkuid2'];
+                        var pkuid3=msg['pkuid3'];
+                        //1:发起三人PK;2;接受三人PK;3:拒绝三人PK;4:三人PK成功通知;5.手动断开三人PK;7:对方正忙碌 8:对方无响应; 9:三人PK结果
+                        
+                        if(action=='1'){
+                            console.log('发起三人PK');
+                            console.log(FormatNowDate());
+                            console.log(socket.uid+'---'+pkuid2+'---'+pkuid3);
+                            
+                            // 检查是否在三人连麦房间中
+                            getRoomMembers(socket.uid, function(members) {
+                                members = members.filter((element) => element !== "");
+                                if(members.length >= 3 && members.includes(pkuid2) && members.includes(pkuid3)) {
+                                    // 向另外两个主播发送PK邀请
+                                    var invite_data = {
+                                        "msg":[{
+                                            "_method_":"LiveThreePK",
+                                            "action":"1",
+                                            "msgtype":"10",
+                                            "uid":""+socket.uid,
+                                            "uname":""+socket.nicename,
+                                            "pkuid2":""+pkuid2,
+                                            "pkuid3":""+pkuid3
+                                        }],
+                                        "retcode":"000000",
+                                        "retmsg":"OK"
+                                    };
+                                    
+                                    var socket_pkuid2=sockets[pkuid2];
+                                    var socket_pkuid3=sockets[pkuid3];
+                                    if(socket_pkuid2){
+                                        socket_pkuid2.emit('broadcastingListen',[JSON.stringify(invite_data)]);
+                                    }
+                                    if(socket_pkuid3){
+                                        socket_pkuid3.emit('broadcastingListen',[JSON.stringify(invite_data)]);
+                                    }
+                                } else {
+                                    // 房间成员不足或不匹配
+                                    var error_data = {
+                                        "msg":[{
+                                            "_method_":"LiveThreePK",
+                                            "action":"7", // 忙碌/不可用
+                                            "msgtype":"10",
+                                            "uid":""+socket.uid
+                                        }],
+                                        "retcode":"000000",
+                                        "retmsg":"OK"
+                                    };
+                                    socket.emit('broadcastingListen',[JSON.stringify(error_data)]);
+                                }
+                            });
+                        }
+                        
+                        if(action=='2'){
+                            /* 接受三人PK并开始 */
+                            console.log('接受三人PK');
+                            console.log(FormatNowDate());
+                            console.log(socket.uid+'---'+pkuid2+'---'+pkuid3);
+                            
+                            var sign_data={uid:socket.uid,pkuid2:pkuid2,pkuid3:pkuid3};
+                            var sign=setSign(sign_data);
+                            request(config['WEBADDRESS']+"?service=Livepk.setThreePK&uid="+socket.uid + "&pkuid2=" + pkuid2+ "&pkuid3=" + pkuid3+ "&sign=" +sign,function(error, response, body){
+                                if(error) return;
+                                console.log('setThreePK response:', body);
+                                var res = evalJson(body);
+                                if( response.statusCode == 200 && res.data.code == 0){
+                                    
+                                    var info = res.data.info[0];
+                                    console.log('三人PK开始成功:', info);
+                                    
+                                    /* 通知三个房间PK开始 */
+                                    var pk_start_data={
+                                        "msg":[{
+                                            "_method_":"LiveThreePK",
+                                            "action":"4",
+                                            "msgtype":"10",
+                                            "uid1":""+socket.uid,
+                                            "uid2":""+pkuid2,
+                                            "uid3":""+pkuid3,
+                                            "room_id":""+info['room_id'],
+                                            "addtime":""+info['addtime']
+                                        }],
+                                        "retcode":"000000",
+                                        "retmsg":"OK"
+                                    };
+                                    
+                                    // 通知三个房间
+                                    process_msg(io,socket.uid,JSON.stringify(pk_start_data));
+                                    process_msg(io,pkuid2,JSON.stringify(pk_start_data));
+                                    process_msg(io,pkuid3,JSON.stringify(pk_start_data));
+                                    
+                                    setTimeout(function() {//定时发送结果 - 5分钟后自动结束
+                                        console.log('三人PK计时器到期');
+                                        console.log(FormatNowDate());
+                                        endThreePk(io,socket.uid,0,info['addtime']);
+                                    }, 5*60*1000);
+                                } else {
+                                    console.log('三人PK开始失败:', res);
+                                }
+                            });
+                        }else if(action=='5'){
+                            /* 手动结束三人PK */
+                            console.log('手动结束三人PK');
+                            console.log(FormatNowDate());
+                            endThreePk(io,socket.uid,1,0);
+                        }else{
+                            // 其他action转发给相关用户
+                            var socket_pkuid2=sockets[pkuid2];
+                            var socket_pkuid3=sockets[pkuid3];
+                            if(socket_pkuid2){
+                                socket_pkuid2.emit('broadcastingListen',[data_str]);
+                            }
+                            if(socket_pkuid3){
+                                socket_pkuid3.emit('broadcastingListen',[data_str]);
+                            }
+                        }
+	                    break;
+			    	}
+					
 			    	
                     case 'goodsLiveShow' :{//商品在直播间展示/不展示
                         process_msg(io,socket.roomnum,data_str);
@@ -1065,6 +1226,53 @@ function endLivePk(io,uid,type,addtime){
     
 }
 
+/* 三人PK结束处理 */
+function endThreePk(io,uid,type,addtime){
+    console.log('结束三人PK');
+    console.log('uid-'+uid);
+    console.log('addtime-'+addtime);
+    console.log('type-'+type);
+    var sign_data={uid:uid,addtime:addtime,type:type};
+    var sign=setSign(sign_data);
+    request(config['WEBADDRESS']+"?service=Livepk.endThreePK&uid="+uid + "&addtime=" + addtime+ "&type=" + type+ "&sign=" +sign,function(error, response, body){
+        if(error) return;
+        console.log('endThreePK response:', body);
+        var res = evalJson(body);
+        if( response.statusCode == 200 && res.data.code == 0){
+            var info=res.data.info[0];
+            var data_obj={
+                    "msg":[
+                        {
+                            "_method_":"LiveThreePK",
+                            "action":"9",
+                            "msgtype":"10",
+                            "win_uid":""+info['win_uid'],
+                            "uid1":""+info['uid1'],
+                            "uid2":""+info['uid2'],
+                            "uid3":""+info['uid3'],
+                            "gift1":""+info['gift1'],
+                            "gift2":""+info['gift2'],
+                            "gift3":""+info['gift3'],
+                            "room_id":""+info['room_id']
+                        }
+                    ],
+                    "retcode":"000000",
+                    "retmsg":"OK"
+                };
+    
+            // 通知三个房间PK结果
+            process_msg(io,info['uid1'],JSON.stringify(data_obj));
+            process_msg(io,info['uid2'],JSON.stringify(data_obj));
+            process_msg(io,info['uid3'],JSON.stringify(data_obj));
+            
+        } else {
+            console.log('三人PK结束失败:', res);
+        }
+        
+    });
+    
+}
+
 
 
 //时间格式化

+ 202 - 0
phalapi/src/app/Api/Livepk.php

@@ -43,6 +43,20 @@ class Livepk extends Api {
 				'type' => array('name' => 'type', 'type' => 'int', 'desc' => '标识'),
 				'sign' => array('name' => 'sign', 'type' => 'string','desc' => '签名'),
 			),
+            
+            'setThreePK' => array(
+                'uid' => array('name' => 'uid', 'type' => 'int', 'desc' => '用户ID'),
+				'pkuid2' => array('name' => 'pkuid2', 'type' => 'int', 'desc' => '连麦主播ID2'),
+				'pkuid3' => array('name' => 'pkuid3', 'type' => 'int', 'desc' => '连麦主播ID3'),
+				'sign' => array('name' => 'sign', 'type' => 'string', 'desc' => '签名'),
+			),
+            
+            'endThreePK' => array(
+                'uid' => array('name' => 'uid', 'type' => 'int', 'desc' => '用户ID'),
+				'addtime' => array('name' => 'addtime', 'type' => 'int', 'desc' => '时间戳'),
+				'type' => array('name' => 'type', 'type' => 'int', 'desc' => '标识'),
+				'sign' => array('name' => 'sign', 'type' => 'string','desc' => '签名'),
+			),
 		);
 	}
 
@@ -520,4 +534,192 @@ class Livepk extends Api {
 		return $rs;			
 	}    
 
+	/**
+	 * 三人PK开始
+	 * @desc 用于三人PK开始处理业务
+	 * @return int code 操作码,0表示成功
+	 * @return array info 
+	 * @return string msg 提示信息
+	 */
+	public function setThreePK() {
+		$rs = array('code' => 0, 'msg' => '', 'info' => array());
+        
+        $uid = \App\checkNull($this->uid);
+		$pkuid2 = \App\checkNull($this->pkuid2);
+		$pkuid3 = \App\checkNull($this->pkuid3);
+		$sign = \App\checkNull($this->sign);
+        
+        $checkdata = array(
+            'uid' => $uid,
+            'pkuid2' => $pkuid2,
+            'pkuid3' => $pkuid3,
+        );
+        
+        $issign = \App\checkSign($checkdata, $sign);
+
+        if(!$issign){
+            $rs['code'] = 1001;
+			$rs['msg'] = \PhalApi\T('签名错误');
+			return $rs;	
+        } 
+        
+        // 检查三人是否都在连麦房间中
+        $room_id = \PhalApi\DI()->redis->hGet('LiveRoomMaster', $uid);
+        if(!$room_id) {
+            $rs['code'] = 1002;
+			$rs['msg'] = \PhalApi\T('未在连麦房间中');
+			return $rs;
+        }
+        
+        $room_members = \PhalApi\DI()->redis->hGet('LiveRoom', $room_id);
+        $members_array = explode(',', $room_members);
+        
+        if(count($members_array) < 3 || !in_array($pkuid2, $members_array) || !in_array($pkuid3, $members_array)) {
+            $rs['code'] = 1003;
+			$rs['msg'] = \PhalApi\T('房间成员不足三人或成员不匹配');
+			return $rs;
+        }
+        
+        $key1 = 'LivePK_Three';
+        $key2 = 'LivePK_Three_gift';
+        $nowtime = time();
+        
+        // 设置三人PK状态
+        $pk_data = json_encode(array(
+            'uid1' => $uid,
+            'uid2' => $pkuid2, 
+            'uid3' => $pkuid3,
+            'room_id' => $room_id
+        ));
+        
+        \PhalApi\DI()->redis->hSet($key1, $room_id, $pk_data);
+        
+        // 初始化礼物统计
+        \PhalApi\DI()->redis->hSet($key2, $uid, 0);
+        \PhalApi\DI()->redis->hSet($key2, $pkuid2, 0);
+        \PhalApi\DI()->redis->hSet($key2, $pkuid3, 0);
+
+        $key3 = 'LivePK_Three_timer';
+        \PhalApi\DI()->redis->hSet($key3, $room_id, $nowtime);
+        
+        $rs['info'][0]['addtime'] = $nowtime;
+        $rs['info'][0]['room_id'] = $room_id;
+
+		return $rs;			
+	}
+
+	/**
+	 * 三人PK结束
+	 * @desc 用于三人PK结束处理业务
+	 * @return int code 操作码,0表示成功
+	 * @return array info 
+	 * @return string msg 提示信息
+	 */
+	public function endThreePK() {
+		$rs = array('code' => 0, 'msg' => '', 'info' => array());
+        
+        $uid = \App\checkNull($this->uid);
+		$addtime = \App\checkNull($this->addtime);
+		$type = \App\checkNull($this->type);
+		$sign = \App\checkNull($this->sign);
+        
+        $checkdata = array(
+            'uid' => $uid,
+            'addtime' => $addtime,
+            'type' => $type,
+        );
+        
+        $issign = \App\checkSign($checkdata, $sign);
+
+        if(!$issign){
+            $rs['code'] = 1001;
+			$rs['msg'] = \PhalApi\T('签名错误');
+			return $rs;	
+        }
+        
+        $room_id = \PhalApi\DI()->redis->hGet('LiveRoomMaster', $uid);
+        if(!$room_id) {
+            $rs['code'] = 1002;
+			$rs['msg'] = \PhalApi\T('未找到房间信息');
+			return $rs;
+        }
+        
+        $key1 = 'LivePK_Three';
+        $key2 = 'LivePK_Three_gift';
+        $key3 = 'LivePK_Three_timer';
+        
+        $pk_data_str = \PhalApi\DI()->redis->hGet($key1, $room_id);
+        if(!$pk_data_str) {
+            $rs['code'] = 1003;
+			$rs['msg'] = \PhalApi\T('PK信息不存在');
+			return $rs;
+        }
+        
+        $pk_data = json_decode($pk_data_str, true);
+        
+        if($type == 0) {
+            $pktime = \PhalApi\DI()->redis->hGet($key3, $room_id);
+            if($pktime != $addtime) {
+                $rs['code'] = 1004;
+                $rs['msg'] = \PhalApi\T('时间不匹配');
+                return $rs;	
+            }
+        }
+        
+        // 获取三人礼物统计
+        $gift_uid1 = \PhalApi\DI()->redis->hGet($key2, $pk_data['uid1']) ?: 0;
+        $gift_uid2 = \PhalApi\DI()->redis->hGet($key2, $pk_data['uid2']) ?: 0;
+        $gift_uid3 = \PhalApi\DI()->redis->hGet($key2, $pk_data['uid3']) ?: 0;
+        
+        // 计算获胜者
+        $win_uid = 0;
+        $max_gift = max($gift_uid1, $gift_uid2, $gift_uid3);
+        
+        if($type == 1) {
+            // 手动结束,不计算胜负
+            $win_uid = 0;
+        } else {
+            // 找出礼物最多的用户
+            if($gift_uid1 == $max_gift && $gift_uid1 > 0) {
+                $win_uid = $pk_data['uid1'];
+            } elseif($gift_uid2 == $max_gift && $gift_uid2 > 0) {
+                $win_uid = $pk_data['uid2'];
+            } elseif($gift_uid3 == $max_gift && $gift_uid3 > 0) {
+                $win_uid = $pk_data['uid3'];
+            }
+            
+            // 如果有并列第一,则为平局
+            $first_count = 0;
+            if($gift_uid1 == $max_gift) $first_count++;
+            if($gift_uid2 == $max_gift) $first_count++;
+            if($gift_uid3 == $max_gift) $first_count++;
+            
+            if($first_count > 1) {
+                $win_uid = 0; // 平局
+            }
+        }
+        
+        // 清除Redis数据
+        \PhalApi\DI()->redis->hDel($key1, $room_id);
+        \PhalApi\DI()->redis->hDel($key2, $pk_data['uid1']);
+        \PhalApi\DI()->redis->hDel($key2, $pk_data['uid2']);
+        \PhalApi\DI()->redis->hDel($key2, $pk_data['uid3']);
+        \PhalApi\DI()->redis->hDel($key3, $room_id);
+        
+        $info = [
+            'win_uid' => $win_uid,
+            'uid1' => $pk_data['uid1'],
+            'uid2' => $pk_data['uid2'],
+            'uid3' => $pk_data['uid3'],
+            'gift1' => $gift_uid1,
+            'gift2' => $gift_uid2,
+            'gift3' => $gift_uid3,
+            'room_id' => $room_id
+        ];
+
+        $rs['info'][0] = $info;
+        
+		return $rs;			
+	}
+
 }

+ 41 - 0
phalapi/src/app/Model/Live.php

@@ -583,6 +583,15 @@ class Live extends NotORM {
         $pktotal1='0';
         $pktotal2='0';
         
+        // 三人PK处理
+        $isthreepk='0';
+        $threepk_uid1='0';
+        $threepk_uid2='0';
+        $threepk_uid3='0';
+        $threepk_total1='0';
+        $threepk_total2='0';
+        $threepk_total3='0';
+        
         $pkuid=\PhalApi\DI()->redis -> hGet($key1,$liveuid);
         if($pkuid){
             $ispk='1';
@@ -598,6 +607,30 @@ class Live extends NotORM {
             $pkuid2=$pkuid;
             
         }
+        
+        // 检查是否在三人PK中
+        $room_id = \PhalApi\DI()->redis->hGet('LiveRoomMaster', $liveuid);
+        if($room_id) {
+            $threepk_data_str = \PhalApi\DI()->redis->hGet('LivePK_Three', $room_id);
+            if($threepk_data_str) {
+                $threepk_data = json_decode($threepk_data_str, true);
+                if($threepk_data && isset($threepk_data['uid1']) && isset($threepk_data['uid2']) && isset($threepk_data['uid3'])) {
+                    $isthreepk='1';
+                    
+                    // 增加礼物统计
+                    \PhalApi\DI()->redis->hIncrBy('LivePK_Three_gift', $liveuid, $total);
+                    
+                    // 获取三人礼物统计
+                    $threepk_total1 = \PhalApi\DI()->redis->hGet('LivePK_Three_gift', $threepk_data['uid1']) ?: 0;
+                    $threepk_total2 = \PhalApi\DI()->redis->hGet('LivePK_Three_gift', $threepk_data['uid2']) ?: 0;
+                    $threepk_total3 = \PhalApi\DI()->redis->hGet('LivePK_Three_gift', $threepk_data['uid3']) ?: 0;
+                    
+                    $threepk_uid1 = $threepk_data['uid1'];
+                    $threepk_uid2 = $threepk_data['uid2'];
+                    $threepk_uid3 = $threepk_data['uid3'];
+                }
+            }
+        }
 
         // 清除缓存
 		\App\delCache("userinfo_".$uid); 
@@ -630,6 +663,14 @@ class Live extends NotORM {
             "pkuid2"=>$pkuid2,
             "pktotal1"=>$pktotal1,
             "pktotal2"=>$pktotal2,
+            // 三人PK相关字段
+            "isthreepk"=>$isthreepk,
+            "threepk_uid1"=>$threepk_uid1,
+            "threepk_uid2"=>$threepk_uid2,
+            "threepk_uid3"=>$threepk_uid3,
+            "threepk_total1"=>$threepk_total1,
+            "threepk_total2"=>$threepk_total2,
+            "threepk_total3"=>$threepk_total3,
 
 		);
 		

+ 304 - 0
三人PK功能说明.md

@@ -0,0 +1,304 @@
+# 三人PK功能实现说明
+
+## 功能概述
+
+基于现有的三人主播连麦和一对一主播PK功能,新增了三人PK功能。该功能允许在三人连麦的基础上进行PK竞赛,通过礼物统计来决定胜负。
+
+## 实现原理
+
+### 1. 数据结构设计
+
+#### Redis键值设计
+- `LivePK_Three`: 存储三人PK房间信息
+  - Key: room_id
+  - Value: JSON格式 `{"uid1": "主播1ID", "uid2": "主播2ID", "uid3": "主播3ID", "room_id": "房间ID"}`
+
+- `LivePK_Three_gift`: 存储三人PK礼物统计
+  - Key: uid (主播ID)
+  - Value: 礼物总价值
+
+- `LivePK_Three_timer`: 存储三人PK开始时间
+  - Key: room_id
+  - Value: 开始时间戳
+
+#### 现有Redis键复用
+- `LiveRoom`: 房间成员列表
+- `LiveRoomMaster`: 用户所在房间映射
+- `LiveConnect`: 连麦关系
+- `LiveConnect_pull`: 拉流地址
+
+### 2. API接口
+
+#### 2.1 开始三人PK
+**接口**: `Livepk.setThreePK`
+
+**参数**:
+- `uid`: 发起者用户ID
+- `pkuid2`: 第二个主播ID  
+- `pkuid3`: 第三个主播ID
+- `sign`: 签名
+
+**返回**:
+```json
+{
+    "code": 0,
+    "msg": "",
+    "info": [{
+        "addtime": 1632123456,
+        "room_id": "12345_1632123456"
+    }]
+}
+```
+
+#### 2.2 结束三人PK
+**接口**: `Livepk.endThreePK`
+
+**参数**:
+- `uid`: 用户ID
+- `addtime`: PK开始时间戳
+- `type`: 结束类型 (0:自动结束, 1:手动结束)
+- `sign`: 签名
+
+**返回**:
+```json
+{
+    "code": 0,
+    "msg": "",
+    "info": [{
+        "win_uid": "获胜者ID",
+        "uid1": "主播1ID",
+        "uid2": "主播2ID", 
+        "uid3": "主播3ID",
+        "gift1": "主播1礼物总值",
+        "gift2": "主播2礼物总值",
+        "gift3": "主播3礼物总值",
+        "room_id": "房间ID"
+    }]
+}
+```
+
+### 3. Socket消息协议
+
+#### 3.1 三人PK消息类型
+**方法**: `LiveThreePK`
+
+**Action类型**:
+- `1`: 发起三人PK
+- `2`: 接受三人PK
+- `3`: 拒绝三人PK
+- `4`: 三人PK开始通知
+- `5`: 手动结束三人PK
+- `7`: 忙碌/不可用
+- `8`: 无响应
+- `9`: 三人PK结果
+
+#### 3.2 消息格式示例
+
+**发起三人PK**:
+```json
+{
+    "msg": [{
+        "_method_": "LiveThreePK",
+        "action": "1",
+        "msgtype": "10",
+        "uid": "发起者ID",
+        "uname": "发起者昵称",
+        "pkuid2": "主播2ID",
+        "pkuid3": "主播3ID"
+    }],
+    "retcode": "000000",
+    "retmsg": "OK"
+}
+```
+
+**PK开始通知**:
+```json
+{
+    "msg": [{
+        "_method_": "LiveThreePK",
+        "action": "4",
+        "msgtype": "10",
+        "uid1": "主播1ID",
+        "uid2": "主播2ID",
+        "uid3": "主播3ID",
+        "room_id": "房间ID",
+        "addtime": "开始时间戳"
+    }],
+    "retcode": "000000",
+    "retmsg": "OK"
+}
+```
+
+**PK结果通知**:
+```json
+{
+    "msg": [{
+        "_method_": "LiveThreePK",
+        "action": "9",
+        "msgtype": "10",
+        "win_uid": "获胜者ID",
+        "uid1": "主播1ID",
+        "uid2": "主播2ID",
+        "uid3": "主播3ID",
+        "gift1": "主播1礼物总值",
+        "gift2": "主播2礼物总值",
+        "gift3": "主播3礼物总值",
+        "room_id": "房间ID"
+    }],
+    "retcode": "000000",
+    "retmsg": "OK"
+}
+```
+
+### 4. 礼物统计机制
+
+#### 4.1 礼物发送增强
+在原有礼物发送基础上,增加三人PK检测:
+
+**新增字段**:
+- `isthreepk`: 是否三人PK (0/1)
+- `threepk_uid1`: 主播1ID
+- `threepk_uid2`: 主播2ID  
+- `threepk_uid3`: 主播3ID
+- `threepk_total1`: 主播1礼物总值
+- `threepk_total2`: 主播2礼物总值
+- `threepk_total3`: 主播3礼物总值
+
+#### 4.2 统计逻辑
+1. 检查主播是否在三人PK房间中
+2. 如果是,则增加对应主播的礼物统计
+3. 返回所有三人的实时统计数据
+4. 前端根据统计数据实时更新PK进度
+
+### 5. 使用流程
+
+#### 5.1 完整流程
+1. **建立三人连麦**: 三个主播先建立连麦关系
+2. **发起三人PK**: 任一主播发起三人PK邀请
+3. **接受PK**: 其他主播接受PK邀请
+4. **PK进行**: 观众送礼物,实时统计各主播礼物价值
+5. **PK结束**: 5分钟后自动结束或手动结束
+6. **结果公布**: 礼物价值最高者获胜,平局则无获胜者
+
+#### 5.2 前端集成示例
+
+**JavaScript客户端代码**:
+```javascript
+// 发起三人PK
+function startThreePK(pkuid2, pkuid3) {
+    var data = {
+        msg: [{
+            _method_: "LiveThreePK",
+            action: "1",
+            msgtype: "10",
+            uid: currentUserId,
+            uname: currentUserName,
+            pkuid2: pkuid2,
+            pkuid3: pkuid3
+        }],
+        token: userToken
+    };
+    socket.emit('broadcast', data);
+}
+
+// 接受三人PK
+function acceptThreePK(uid, pkuid2, pkuid3) {
+    var data = {
+        msg: [{
+            _method_: "LiveThreePK", 
+            action: "2",
+            msgtype: "10",
+            uid: uid,
+            pkuid2: pkuid2,
+            pkuid3: pkuid3
+        }],
+        token: userToken
+    };
+    socket.emit('broadcast', data);
+}
+
+// 监听PK消息
+socket.on('broadcastingListen', function(data) {
+    var msg = JSON.parse(data[0]);
+    if(msg.msg[0]._method_ === 'LiveThreePK') {
+        switch(msg.msg[0].action) {
+            case '1': // PK邀请
+                showPKInvite(msg.msg[0]);
+                break;
+            case '4': // PK开始
+                startPKTimer(msg.msg[0]);
+                break;
+            case '9': // PK结果
+                showPKResult(msg.msg[0]);
+                break;
+        }
+    }
+});
+```
+
+## 6. 修改文件清单
+
+### 6.1 后端文件
+1. `phalapi/src/app/Api/Livepk.php` - 新增三人PK API接口
+2. `phalapi/src/app/Model/Live.php` - 修改礼物发送逻辑,支持三人PK统计
+3. `dspIM/s1.js` - 新增三人PK Socket处理逻辑
+
+### 6.2 主要修改点
+- **API层**: 新增 `setThreePK` 和 `endThreePK` 方法
+- **Model层**: 在 `sendGift` 方法中增加三人PK检测和统计
+- **Socket层**: 新增 `LiveThreePK` 消息处理和 `endThreePk` 函数
+
+## 7. 兼容性说明
+
+### 7.1 向后兼容
+- 现有的一对一PK功能完全保持不变
+- 现有的三人连麦功能完全保持不变
+- 新增功能不影响现有业务逻辑
+
+### 7.2 最小改动原则
+- 复用现有的房间管理机制
+- 复用现有的礼物发送机制
+- 复用现有的Socket通信机制
+- 仅在必要位置增加三人PK相关逻辑
+
+## 8. 测试建议
+
+### 8.1 功能测试
+1. 三人连麦建立后发起PK
+2. PK过程中礼物统计准确性
+3. PK自动结束和手动结束
+4. 异常情况处理(断线重连等)
+
+### 8.2 性能测试
+1. 多个三人PK房间同时进行
+2. 高频礼物发送时的统计性能
+3. Redis内存使用情况
+
+### 8.3 兼容性测试
+1. 确保一对一PK功能正常
+2. 确保三人连麦功能正常
+3. 确保普通礼物发送功能正常
+
+## 9. 部署说明
+
+### 9.1 部署步骤
+1. 备份现有代码
+2. 更新后端PHP文件
+3. 重启Socket服务器
+4. 更新前端代码(如需要)
+5. 测试功能完整性
+
+### 9.2 回滚方案
+如果出现问题,可以快速回滚到备份版本,因为新功能是增量式的,不会破坏现有数据结构。
+
+## 10. 总结
+
+本次三人PK功能的实现严格遵循了最小改动原则,在现有架构基础上进行扩展,确保了:
+
+1. **功能完整性**: 支持完整的三人PK流程
+2. **向后兼容**: 不影响现有功能
+3. **代码质量**: 遵循现有代码规范
+4. **性能优化**: 复用现有机制,避免重复开发
+5. **易于维护**: 代码结构清晰,便于后续维护
+
+该实现方案可以直接部署使用,为平台增加更丰富的互动玩法。