ITPub博客

首页 > 应用开发 > IT综合 > 体育赛事直播系统开发:实现用户群聊和发红包功能的关键部分代码

体育赛事直播系统开发:实现用户群聊和发红包功能的关键部分代码

IT综合 作者:小兔崽子程序员 时间:2025-04-09 14:33:57 0 删除 编辑

本方案基于“东莞梦幻网络科技”体育赛事直播系统的聊一聊功能模块,实现群聊与发红包的核心功能。技术栈包括后端PHP-ThinkPHP、安卓-Java、iOS-OC及PC/H5-Vue.js。数据库采用MySQL设计,包含群组、成员、消息、红包及其领取记录表。后端提供创建群组、发送消息和红包、领取红包等API接口;前端Vue.js实现群聊界面与WebSocket实时消息推送;移动端(Android/iOS)通过WebSocket接收消息并展示。整体架构支持多平台交互,确保实时性与用户体验。

数据库表设计(MySQL)

-- 群组表
CREATE TABLE `groups` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `creator_id` int(11) NOT NULL,
  `avatar` varchar(255) DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
);
-- 群成员表
CREATE TABLE `group_members` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `group_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `role` tinyint(1) DEFAULT '0' COMMENT '0-普通成员 1-管理员 2-群主',
  `joined_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `group_user` (`group_id`,`user_id`)
);
-- 消息表
CREATE TABLE `messages` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `group_id` int(11) NOT NULL,
  `sender_id` int(11) NOT NULL,
  `content` text NOT NULL,
  `type` tinyint(1) DEFAULT '0' COMMENT '0-文本 1-图片 2-红包 3-系统通知',
  `created_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `group_id` (`group_id`)
);
-- 红包表
CREATE TABLE `red_packets` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `group_id` int(11) NOT NULL,
  `sender_id` int(11) NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `count` int(11) NOT NULL,
  `remain_amount` decimal(10,2) NOT NULL,
  `remain_count` int(11) NOT NULL,
  `message` varchar(255) DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `expire_at` datetime NOT NULL,
  `status` tinyint(1) DEFAULT '0' COMMENT '0-未领完 1-已领完 2-已过期',
  PRIMARY KEY (`id`)
);
-- 红包领取记录
CREATE TABLE `red_packet_records` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `red_packet_id` int(11) NOT NULL,
  `receiver_id` int(11) NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `received_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `red_packet_id` (`red_packet_id`)
);

后端实现 (ThinkPHP)

群聊API控制器

<?php
namespace app\api\controller;
use think\Controller;
use think\Request;
class Group extends Controller
{
    // 创建群组
    public function create()
    {
        $user_id = Request::instance()->param('user_id');
        $name = Request::instance()->param('name');
        
        $group_id = Db::name('groups')->insertGetId([
            'name' => $name,
            'creator_id' => $user_id,
            'created_at' => date('Y-m-d H:i:s'),
            'updated_at' => date('Y-m-d H:i:s')
        ]);
        
        // 添加创建者为群主
        Db::name('group_members')->insert([
            'group_id' => $group_id,
            'user_id' => $user_id,
            'role' => 2, // 群主
            'joined_at' => date('Y-m-d H:i:s')
        ]);
        
        return json(['code' => 0, 'data' => ['group_id' => $group_id]]);
    }
    
    // 发送群消息
    public function sendMessage()
    {
        $group_id = Request::instance()->param('group_id');
        $user_id = Request::instance()->param('user_id');
        $content = Request::instance()->param('content');
        
        // 检查是否是群成员
        $is_member = Db::name('group_members')
            ->where('group_id', $group_id)
            ->where('user_id', $user_id)
            ->count();
            
        if(!$is_member) {
            return json(['code' => 1, 'msg' => '您不是该群成员']);
        }
        
        // 保存消息到数据库
        $message_id = Db::name('messages')->insertGetId([
            'group_id' => $group_id,
            'sender_id' => $user_id,
            'content' => $content,
            'type' => 0,
            'created_at' => date('Y-m-d H:i:s')
        ]);
        
        // 通过WebSocket推送消息
        // 实际实现中应该调用WebSocket服务推送
        
        return json(['code' => 0, 'data' => ['message_id' => $message_id]]);
    }
    
    // 发送红包
    public function sendRedPacket()
    {
        $group_id = Request::instance()->param('group_id');
        $user_id = Request::instance()->param('user_id');
        $amount = Request::instance()->param('amount');
        $count = Request::instance()->param('count');
        $message = Request::instance()->param('message', '');
        
        // 检查余额等逻辑
        
        // 创建红包
        $red_packet_id = Db::name('red_packets')->insertGetId([
            'group_id' => $group_id,
            'sender_id' => $user_id,
            'amount' => $amount,
            'count' => $count,
            'remain_amount' => $amount,
            'remain_count' => $count,
            'message' => $message,
            'created_at' => date('Y-m-d H:i:s'),
            'expire_at' => date('Y-m-d H:i:s', time() + 86400), // 24小时后过期
            'status' => 0
        ]);
        
        // 保存消息
        $message_id = Db::name('messages')->insertGetId([
            'group_id' => $group_id,
            'sender_id' => $user_id,
            'content' => json_encode(['red_packet_id' => $red_packet_id]),
            'type' => 2, // 红包消息
            'created_at' => date('Y-m-d H:i:s')
        ]);
        
        return json(['code' => 0, 'data' => ['red_packet_id' => $red_packet_id]]);
    }
    
    // 领取红包
    public function receiveRedPacket()
    {
        $red_packet_id = Request::instance()->param('red_packet_id');
        $user_id = Request::instance()->param('user_id');
        
        // 检查红包状态
        $red_packet = Db::name('red_packets')->find($red_packet_id);
        if(!$red_packet || $red_packet['status'] != 0) {
            return json(['code' => 1, 'msg' => '红包已领取完或已过期']);
        }
        
        // 检查是否已领取
        $has_received = Db::name('red_packet_records')
            ->where('red_packet_id', $red_packet_id)
            ->where('receiver_id', $user_id)
            ->count();
            
        if($has_received) {
            return json(['code' => 2, 'msg' => '您已领取过该红包']);
        }
        
        // 计算领取金额
        $amount = $this->calculateRedPacketAmount($red_packet);
        
        // 更新红包状态
        Db::name('red_packets')
            ->where('id', $red_packet_id)
            ->update([
                'remain_amount' => Db::raw('remain_amount-' . $amount),
                'remain_count' => Db::raw('remain_count-1'),
                'status' => $red_packet['remain_count'] == 1 ? 1 : 0
            ]);
        
        // 添加领取记录
        Db::name('red_packet_records')->insert([
            'red_packet_id' => $red_packet_id,
            'receiver_id' => $user_id,
            'amount' => $amount,
            'received_at' => date('Y-m-d H:i:s')
        ]);
        
        // 更新用户余额等逻辑
        
        return json(['code' => 0, 'data' => ['amount' => $amount]]);
    }
    
    private function calculateRedPacketAmount($red_packet)
    {
        // 简单实现:平均分配
        if($red_packet['remain_count'] == 1) {
            return $red_packet['remain_amount'];
        }
        
        $avg = $red_packet['remain_amount'] / $red_packet['remain_count'];
        $min = 0.01;
        $max = $avg * 2;
        $amount = mt_rand($min * 100, $max * 100) / 100;
        $amount = min($amount, $red_packet['remain_amount'] - ($red_packet['remain_count'] - 1) * 0.01);
        
        return round($amount, 2);
    }
}


前端实现 (Vue.js)
群聊主界面组件

<template>
  <div class="group-chat-container">
    <!-- 群聊头部 -->
    <div class="chat-header">
      <h2>{{ groupName }}</h2>
      <div class="header-actions">
        <button @click="showGroupInfo">群信息</button>
        <button @click="showRedPacketDialog">发红包</button>
      </div>
    </div>
    
    <!-- 消息列表 -->
    <div class="message-list" ref="messageList">
      <div v-for="(message, index) in messages" :key="index" 
           :class="['message-item', message.sender_id === currentUserId ? 'self' : 'other']">
        <div v-if="message.type === 0" class="text-message">
          <div class="sender-name" v-if="message.sender_id !== currentUserId">
            {{ getMemberName(message.sender_id) }}
          </div>
          <div class="message-content">{{ message.content }}</div>
          <div class="message-time">{{ formatTime(message.created_at) }}</div>
        </div>
        
        <div v-else-if="message.type === 2" class="red-packet-message">
          <div class="sender-name">{{ getMemberName(message.sender_id) }}的红包</div>
          <div class="red-packet-content" @click="openRedPacket(message)">
            <div class="red-packet-icon">🧧</div>
            <div class="red-packet-message-text">{{ getRedPacketMessage(message) }}</div>
          </div>
          <div class="message-time">{{ formatTime(message.created_at) }}</div>
        </div>
      </div>
    </div>
    
    <!-- 输入框 -->
    <div class="message-input">
      <input v-model="inputMessage" @keyup.enter="sendMessage" placeholder="输入消息...">
      <button @click="sendMessage">发送</button>
    </div>
    
    <!-- 红包对话框 -->
    <div v-if="showRedPacket" class="red-packet-dialog">
      <div class="red-packet-box">
        <h3>发红包</h3>
        <div class="red-packet-form">
          <div class="form-item">
            <label>金额</label>
            <input type="number" v-model="redPacketAmount" placeholder="输入金额">
          </div>
          <div class="form-item">
            <label>个数</label>
            <input type="number" v-model="redPacketCount" placeholder="输入红包个数">
          </div>
          <div class="form-item">
            <label>留言</label>
            <input v-model="redPacketMessage" placeholder="恭喜发财">
          </div>
          <div class="form-actions">
            <button @click="sendRedPacket">塞钱进红包</button>
            <button @click="showRedPacket = false">取消</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      groupId: null,
      groupName: '群聊名称',
      currentUserId: 1, // 当前用户ID
      messages: [],
      inputMessage: '',
      showRedPacket: false,
      redPacketAmount: '',
      redPacketCount: 1,
      redPacketMessage: '恭喜发财',
      members: [],
      ws: null
    }
  },
  
  mounted() {
    this.groupId = this.$route.params.groupId;
    this.loadGroupInfo();
    this.loadMessages();
    this.connectWebSocket();
  },
  
  methods: {
    async loadGroupInfo() {
      try {
        const response = await this.$http.get(`/api/group/info/${this.groupId}`);
        this.groupName = response.data.name;
        this.members = response.data.members;
      } catch (error) {
        console.error('获取群信息失败:', error);
      }
    },
    
    async loadMessages() {
      try {
        const response = await this.$http.get(`/api/group/messages/${this.groupId}`);
        this.messages = response.data;
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      } catch (error) {
        console.error('获取消息失败:', error);
      }
    },
    
    connectWebSocket() {
      this.ws = new WebSocket(`ws://your-websocket-server:2346?user_id=${this.currentUserId}`);
      
      this.ws.onmessage = (event) => {
        const message = JSON.parse(event.data);
        if(message.group_id === this.groupId) {
          this.messages.push(message);
          this.$nextTick(() => {
            this.scrollToBottom();
          });
        }
      };
      
      this.ws.onclose = () => {
        console.log('WebSocket连接关闭');
      };
    },
    
    sendMessage() {
      if(!this.inputMessage.trim()) return;
      
      const message = {
        type: 'group_message',
        group_id: this.groupId,
        sender_id: this.currentUserId,
        content: this.inputMessage
      };
      
      this.ws.send(JSON.stringify(message));
      
      // 添加到本地消息列表
      this.messages.push({
        group_id: this.groupId,
        sender_id: this.currentUserId,
        content: this.inputMessage,
        type: 0,
        created_at: new Date().toISOString()
      });
      
      this.inputMessage = '';
      this.$nextTick(() => {
        this.scrollToBottom();
      });
    },
    
    scrollToBottom() {
      const container = this.$refs.messageList;
      container.scrollTop = container.scrollHeight;
    },
    
    showRedPacketDialog() {
      this.showRedPacket = true;
    },
    
    async sendRedPacket() {
      try {
        const response = await this.$http.post('/api/group/sendRedPacket', {
          group_id: this.groupId,
          user_id: this.currentUserId,
          amount: this.redPacketAmount,
          count: this.redPacketCount,
          message: this.redPacketMessage
        });
        
        // 添加到消息列表
        this.messages.push({
          group_id: this.groupId,
          sender_id: this.currentUserId,
          content: JSON.stringify({red_packet_id: response.data.red_packet_id}),
          type: 2,
          created_at: new Date().toISOString()
        });
        
        this.showRedPacket = false;
        this.redPacketAmount = '';
        this.redPacketCount = 1;
        this.redPacketMessage = '恭喜发财';
        
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      } catch (error) {
        console.error('发送红包失败:', error);
      }
    },
    
    async openRedPacket(message) {
      try {
        const content = JSON.parse(message.content);
        const response = await this.$http.post('/api/group/receiveRedPacket', {
          red_packet_id: content.red_packet_id,
          user_id: this.currentUserId
        });
        
        alert(`恭喜您领取了${response.data.amount}元红包`);
      } catch (error) {
        console.error('领取红包失败:', error);
        alert(error.response?.data?.msg || '领取红包失败');
      }
    },
    
    getMemberName(userId) {
      const member = this.members.find(m => m.user_id === userId);
      return member ? member.name : '未知用户';
    },
    
    getRedPacketMessage(message) {
      try {
        const content = JSON.parse(message.content);
        return content.message || '恭喜发财';
      } catch {
        return '恭喜发财';
      }
    },
    
    formatTime(time) {
      return new Date(time).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
    },
    
    showGroupInfo() {
      // 显示群信息
    }
  },
  
  beforeDestroy() {
    if(this.ws) {
      this.ws.close();
    }
  }
}
</script>
<style scoped>
.group-chat-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
}
.chat-header {
  padding: 10px;
  background: #f5f5f5;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.message-list {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
}
.message-item {
  margin-bottom: 15px;
}
.message-item.self {
  text-align: right;
}
.message-item.other {
  text-align: left;
}
.sender-name {
  font-size: 12px;
  color: #666;
  margin-bottom: 5px;
}
.message-content {
  display: inline-block;
  padding: 8px 12px;
  background: #e6f7ff;
  border-radius: 4px;
  max-width: 70%;
  word-break: break-word;
}
.message-item.self .message-content {
  background: #69c0ff;
  color: white;
}
.message-time {
  font-size: 10px;
  color: #999;
  margin-top: 3px;
}
.message-input {
  padding: 10px;
  display: flex;
  border-top: 1px solid #eee;
}
.message-input input {
  flex: 1;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
  margin-right: 10px;
}
.red-packet-message {
  cursor: pointer;
}
.red-packet-content {
  display: inline-flex;
  align-items: center;
  padding: 8px 12px;
  background: #ff4d4f;
  color: white;
  border-radius: 4px;
}
.red-packet-icon {
  font-size: 20px;
  margin-right: 8px;
}
.red-packet-dialog {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}
.red-packet-box {
  background: white;
  padding: 20px;
  border-radius: 8px;
  width: 300px;
}
.red-packet-form .form-item {
  margin-bottom: 15px;
}
.red-packet-form label {
  display: block;
  margin-bottom: 5px;
  font-weight: bold;
}
.red-packet-form input {
  width: 100%;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
}
.form-actions {
  display: flex;
  justify-content: space-between;
  margin-top: 20px;
}
.form-actions button {
  padding: 8px 15px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.form-actions button:first-child {
  background: #ff4d4f;
  color: white;
}
.form-actions button:last-child {
  background: #f5f5f5;
}
</style>

Android实现 (Java)

<template>
  <div class="group-chat-container">
    <!-- 群聊头部 -->
    <div class="chat-header">
      <h2>{{ groupName }}</h2>
      <div class="header-actions">
        <button @click="showGroupInfo">群信息</button>
        <button @click="showRedPacketDialog">发红包</button>
      </div>
    </div>
    
    <!-- 消息列表 -->
    <div class="message-list" ref="messageList">
      <div v-for="(message, index) in messages" :key="index" 
           :class="['message-item', message.sender_id === currentUserId ? 'self' : 'other']">
        <div v-if="message.type === 0" class="text-message">
          <div class="sender-name" v-if="message.sender_id !== currentUserId">
            {{ getMemberName(message.sender_id) }}
          </div>
          <div class="message-content">{{ message.content }}</div>
          <div class="message-time">{{ formatTime(message.created_at) }}</div>
        </div>
        
        <div v-else-if="message.type === 2" class="red-packet-message">
          <div class="sender-name">{{ getMemberName(message.sender_id) }}的红包</div>
          <div class="red-packet-content" @click="openRedPacket(message)">
            <div class="red-packet-icon">🧧</div>
            <div class="red-packet-message-text">{{ getRedPacketMessage(message) }}</div>
          </div>
          <div class="message-time">{{ formatTime(message.created_at) }}</div>
        </div>
      </div>
    </div>
    
    <!-- 输入框 -->
    <div class="message-input">
      <input v-model="inputMessage" @keyup.enter="sendMessage" placeholder="输入消息...">
      <button @click="sendMessage">发送</button>
    </div>
    
    <!-- 红包对话框 -->
    <div v-if="showRedPacket" class="red-packet-dialog">
      <div class="red-packet-box">
        <h3>发红包</h3>
        <div class="red-packet-form">
          <div class="form-item">
            <label>金额</label>
            <input type="number" v-model="redPacketAmount" placeholder="输入金额">
          </div>
          <div class="form-item">
            <label>个数</label>
            <input type="number" v-model="redPacketCount" placeholder="输入红包个数">
          </div>
          <div class="form-item">
            <label>留言</label>
            <input v-model="redPacketMessage" placeholder="恭喜发财">
          </div>
          <div class="form-actions">
            <button @click="sendRedPacket">塞钱进红包</button>
            <button @click="showRedPacket = false">取消</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      groupId: null,
      groupName: '群聊名称',
      currentUserId: 1, // 当前用户ID
      messages: [],
      inputMessage: '',
      showRedPacket: false,
      redPacketAmount: '',
      redPacketCount: 1,
      redPacketMessage: '恭喜发财',
      members: [],
      ws: null
    }
  },
  
  mounted() {
    this.groupId = this.$route.params.groupId;
    this.loadGroupInfo();
    this.loadMessages();
    this.connectWebSocket();
  },
  
  methods: {
    async loadGroupInfo() {
      try {
        const response = await this.$http.get(`/api/group/info/${this.groupId}`);
        this.groupName = response.data.name;
        this.members = response.data.members;
      } catch (error) {
        console.error('获取群信息失败:', error);
      }
    },
    
    async loadMessages() {
      try {
        const response = await this.$http.get(`/api/group/messages/${this.groupId}`);
        this.messages = response.data;
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      } catch (error) {
        console.error('获取消息失败:', error);
      }
    },
    
    connectWebSocket() {
      this.ws = new WebSocket(`ws://your-websocket-server:2346?user_id=${this.currentUserId}`);
      
      this.ws.onmessage = (event) => {
        const message = JSON.parse(event.data);
        if(message.group_id === this.groupId) {
          this.messages.push(message);
          this.$nextTick(() => {
            this.scrollToBottom();
          });
        }
      };
      
      this.ws.onclose = () => {
        console.log('WebSocket连接关闭');
      };
    },
    
    sendMessage() {
      if(!this.inputMessage.trim()) return;
      
      const message = {
        type: 'group_message',
        group_id: this.groupId,
        sender_id: this.currentUserId,
        content: this.inputMessage
      };
      
      this.ws.send(JSON.stringify(message));
      
      // 添加到本地消息列表
      this.messages.push({
        group_id: this.groupId,
        sender_id: this.currentUserId,
        content: this.inputMessage,
        type: 0,
        created_at: new Date().toISOString()
      });
      
      this.inputMessage = '';
      this.$nextTick(() => {
        this.scrollToBottom();
      });
    },
    
    scrollToBottom() {
      const container = this.$refs.messageList;
      container.scrollTop = container.scrollHeight;
    },
    
    showRedPacketDialog() {
      this.showRedPacket = true;
    },
    
    async sendRedPacket() {
      try {
        const response = await this.$http.post('/api/group/sendRedPacket', {
          group_id: this.groupId,
          user_id: this.currentUserId,
          amount: this.redPacketAmount,
          count: this.redPacketCount,
          message: this.redPacketMessage
        });
        
        // 添加到消息列表
        this.messages.push({
          group_id: this.groupId,
          sender_id: this.currentUserId,
          content: JSON.stringify({red_packet_id: response.data.red_packet_id}),
          type: 2,
          created_at: new Date().toISOString()
        });
        
        this.showRedPacket = false;
        this.redPacketAmount = '';
        this.redPacketCount = 1;
        this.redPacketMessage = '恭喜发财';
        
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      } catch (error) {
        console.error('发送红包失败:', error);
      }
    },
    
    async openRedPacket(message) {
      try {
        const content = JSON.parse(message.content);
        const response = await this.$http.post('/api/group/receiveRedPacket', {
          red_packet_id: content.red_packet_id,
          user_id: this.currentUserId
        });
        
        alert(`恭喜您领取了${response.data.amount}元红包`);
      } catch (error) {
        console.error('领取红包失败:', error);
        alert(error.response?.data?.msg || '领取红包失败');
      }
    },
    
    getMemberName(userId) {
      const member = this.members.find(m => m.user_id === userId);
      return member ? member.name : '未知用户';
    },
    
    getRedPacketMessage(message) {
      try {
        const content = JSON.parse(message.content);
        return content.message || '恭喜发财';
      } catch {
        return '恭喜发财';
      }
    },
    
    formatTime(time) {
      return new Date(time).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
    },
    
    showGroupInfo() {
      // 显示群信息
    }
  },
  
  beforeDestroy() {
    if(this.ws) {
      this.ws.close();
    }
  }
}
</script>
<style scoped>
.group-chat-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
}
.chat-header {
  padding: 10px;
  background: #f5f5f5;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.message-list {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
}
.message-item {
  margin-bottom: 15px;
}
.message-item.self {
  text-align: right;
}
.message-item.other {
  text-align: left;
}
.sender-name {
  font-size: 12px;
  color: #666;
  margin-bottom: 5px;
}
.message-content {
  display: inline-block;
  padding: 8px 12px;
  background: #e6f7ff;
  border-radius: 4px;
  max-width: 70%;
  word-break: break-word;
}
.message-item.self .message-content {
  background: #69c0ff;
  color: white;
}
.message-time {
  font-size: 10px;
  color: #999;
  margin-top: 3px;
}
.message-input {
  padding: 10px;
  display: flex;
  border-top: 1px solid #eee;
}
.message-input input {
  flex: 1;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
  margin-right: 10px;
}
.red-packet-message {
  cursor: pointer;
}
.red-packet-content {
  display: inline-flex;
  align-items: center;
  padding: 8px 12px;
  background: #ff4d4f;
  color: white;
  border-radius: 4px;
}
.red-packet-icon {
  font-size: 20px;
  margin-right: 8px;
}
.red-packet-dialog {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}
.red-packet-box {
  background: white;
  padding: 20px;
  border-radius: 8px;
  width: 300px;
}
.red-packet-form .form-item {
  margin-bottom: 15px;
}
.red-packet-form label {
  display: block;
  margin-bottom: 5px;
  font-weight: bold;
}
.red-packet-form input {
  width: 100%;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
}
.form-actions {
  display: flex;
  justify-content: space-between;
  margin-top: 20px;
}
.form-actions button {
  padding: 8px 15px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.form-actions button:first-child {
  background: #ff4d4f;
  color: white;
}
.form-actions button:last-child {
  background: #f5f5f5;
}
</style>

iOS实现 (Objective-C)

#import "ChatWebSocketClient.h"
#import "SRWebSocket.h"
@interface ChatWebSocketClient () <SRWebSocketDelegate>
@property (nonatomic, strong) SRWebSocket *webSocket;
@property (nonatomic, weak) id<ChatMessageDelegate> delegate;
@end
@implementation ChatWebSocketClient
- (instancetype)initWithURL:(NSURL *)url delegate:(id<ChatMessageDelegate>)delegate {
    self = [super init];
    if (self) {
        _delegate = delegate;
        _webSocket = [[SRWebSocket alloc] initWithURL:url];
        _webSocket.delegate = self;
        [_webSocket open];
    }
    return self;
}
- (void)sendMessage:(NSDictionary *)message {
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:message options:0 error:&error];
    if (!error) {
        NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
        [_webSocket send:jsonString];
    }
}
- (void)close {
    [_webSocket close];
}
#pragma mark - SRWebSocketDelegate
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
    NSLog(@"WebSocket连接已打开");
}
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
    NSLog(@"收到消息: %@", message);
    
    if ([message isKindOfClass:[NSString class]]) {
        NSError *error;
        NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[message dataUsingEncoding:NSUTF8StringEncoding] 
                                                           options:0 
                                                             error:&error];
        if (!error) {
            NSString *type = json[@"type"];
            if ([type isEqualToString:@"group_message"]) {
                NSInteger groupId = [json[@"group_id"] integerValue];
                NSInteger senderId = [json[@"sender_id"] integerValue];
                NSString *content = json[@"content"];
                NSString *time = json[@"time"];
                
                if ([self.delegate respondsToSelector:@selector(didReceiveGroupMessage:groupId:senderId:content:time:)]) {
                    [self.delegate didReceiveGroupMessage:self groupId:groupId senderId:senderId content:content time:time];
                }
            } else if ([type isEqualToString:@"red_packet"]) {
                // 处理红包消息
            }
        }
    }
}
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
    NSLog(@"WebSocket错误: %@", error);
}
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
    NSLog(@"WebSocket连接已关闭: %@", reason);
}
@end


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70044681/viewspace-3080429/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2025-03-22

  • 博文量
    7
  • 访问量
    8358