diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php new file mode 100644 index 00000000..ec1687e4 --- /dev/null +++ b/app/Http/Controllers/AuthController.php @@ -0,0 +1,48 @@ +service = new UserService(); + } + + /** + * @Method POST + * @return JsonResponse + */ + public function login(): JsonResponse + { + $username = request()->input('username'); + $password = request()->input('password'); + + return jok( + $this->service->login($username, $password), + '登录成功' + ); + } + /** + * @Method POST + * @return JsonResponse + */ + public function register(): JsonResponse + { + $username = request()->input('username'); + $password = request()->input('password'); + $nickName = request()->input('nickname'); + + return jok( + $this->service->register($username, $password, $nickName), + '注册成功' + ); + } +} diff --git a/app/Http/Controllers/ImController.php b/app/Http/Controllers/ImController.php new file mode 100644 index 00000000..cb5a963c --- /dev/null +++ b/app/Http/Controllers/ImController.php @@ -0,0 +1,28 @@ +service = ImService::getInstance(); + } + public function bind() + { + $clientId = request()->input('client_id'); + + try { + return jok($this->service->bindClientIdByUserId($clientId)); + } catch (\Exception $e) { + return jerr($e->getMessage()); + } + } +} diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php new file mode 100644 index 00000000..b754608e --- /dev/null +++ b/app/Http/Controllers/UserController.php @@ -0,0 +1,10 @@ +header('token'); + $this->userId = $token; + } + + // 单例 + + public static function getInstance() + { + if (!self::$instance instanceof self) { + self::$instance = new self(); + } + return self::$instance; + } +} diff --git a/app/Services/GatewayWorker/ImService.php b/app/Services/GatewayWorker/ImService.php index 77c5bf98..8b80e4a8 100644 --- a/app/Services/GatewayWorker/ImService.php +++ b/app/Services/GatewayWorker/ImService.php @@ -2,7 +2,19 @@ namespace App\Services\GatewayWorker; -class ImService +use App\Services\Base\BaseService; + +class ImService extends BaseService { + public function bindClientIdByUserId($clientId) + { + if (empty($clientId)) { + throw new \Exception('clientId不能为空'); + } + + GatewayClientService::getInstance()->init()->bindUser($clientId, $this->userId); + + return ['绑定成功']; + } } diff --git a/app/Services/GatewayWorker/UserService.php b/app/Services/GatewayWorker/UserService.php new file mode 100644 index 00000000..ff04f36f --- /dev/null +++ b/app/Services/GatewayWorker/UserService.php @@ -0,0 +1,40 @@ +first(); + if ($userModel) { + if ($userModel->password == md5($password)) { + return [ + 'token' => $userModel->id, + 'user_info' => $userModel + ]; + } else { + return false; + } + } else { + return false; + } + } + + public function register($username, $password, $nickName) + { + $userModel = UserModel::create([ + 'username' => $username, + 'password' => md5($password), + 'nick_name' => $nickName, + 'created_at' => time() + ]); + + return [ + 'token' => $userModel->id, + 'user_info' => $userModel + ]; + } +} diff --git a/bootstrap/app.php b/bootstrap/app.php index c1832766..c3928c57 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -7,6 +7,7 @@ use Illuminate\Foundation\Configuration\Middleware; return Application::configure(basePath: dirname(__DIR__)) ->withRouting( web: __DIR__.'/../routes/web.php', + api: __DIR__.'/../routes/api.php', commands: __DIR__.'/../routes/console.php', health: '/up', ) diff --git a/config/gateway.php b/config/gateway.php index e14b6165..aff0910b 100644 --- a/config/gateway.php +++ b/config/gateway.php @@ -4,8 +4,8 @@ return [ /* * -----------服务地址----------- */ -// 'register_address' => 'http://t-ws.nailaoyun.cn/register/' -// 'register_address' => 't-ws.nailaoyun.cn/register/', +// 'register_address' => 'http://t-ws.奶酪yun.cn/register/' +// 'register_address' => 't-ws.奶酪yun.cn/register/', 'register_address' => '10.0.12.17:11238', // 'register_address' => '101.43.12.11:11238', // 'register_address' => '172.22.240.1:11238', diff --git a/config/helpers.php b/config/helpers.php new file mode 100644 index 00000000..112c9323 --- /dev/null +++ b/config/helpers.php @@ -0,0 +1,80 @@ + $value) { + + // 获取控制器$value的所有方法 + $methods = (new ReflectionClass($value))->getMethods(); + + // 注册路由 + foreach ($methods as $method) { + // 获取方法注释 @Method + $docComment = $method->getDocComment(); + if ($method->name === '__construct' || preg_match('/@Method\s+(NO)\b/', $docComment, $matches)) { + continue; + } + + $httpMethod = 'any'; + // 查询 @Method GET 或者 @Method POST + if (preg_match('/@Method\s+(GET|POST|PUT|DELETE|PATCH|OPTIONS|HEAD|ANY)\b/', $docComment, $matches)) { + $httpMethod = $matches[1]; + } + Illuminate\Support\Facades\Route::$httpMethod( $key. '/'. cc_camel_case_to_dash($method->getName()), [$value, conjunction_symbol_processing($method->name)] ); + } + } + } +} + +/** + * 连赐福转换小驼峰 + * @param $string + * @return string + */ +if(!function_exists('conjunction_symbol_processing')) { + function conjunction_symbol_processing($string): string + { + $string = str_replace('-', ' ', $string); // 将连字符替换为空格 + $string = ucwords($string); // 将每个单词的首字母大写 + $string = str_replace(' ', '', $string); // 空格删除 + $string[0] = lcfirst($string)[0]; // 首字母小写 + + return $string; + } + +} + + + +// 小驼峰转换- +if ( !function_exists('cc_camel_case_to_dash') ) { + function cc_camel_case_to_dash($str): string + { + return strtolower(preg_replace('/([a-z])([A-Z])/', '$1-$2', $str)); + } +} diff --git a/resources/views/chat.blade.php b/resources/views/chat.blade.php new file mode 100644 index 00000000..ced7281e --- /dev/null +++ b/resources/views/chat.blade.php @@ -0,0 +1,899 @@ + + + + + + 奶酪云聊天室 + + + + + + +
+
+ 未连接 +
+ + +
+
+
+
U
+

奶酪云聊天室

+
+ +
+ +
+
+
在线用户 (0)
+
+ +
+
+ +
+
+
+ +

开始聊天吧!您发送的消息将在这里显示

+
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+
+
+
+
+ + + + diff --git a/resources/views/login.blade.php b/resources/views/login.blade.php new file mode 100644 index 00000000..10cae773 --- /dev/null +++ b/resources/views/login.blade.php @@ -0,0 +1,638 @@ + + + + + + 奶酪云聊天室 - 登录 + + + + + +
+
+

欢迎来到奶酪云聊天室

+

安全通讯 · 暗色主题 · 极致体验

+ +
+
+
+ +
+
端到端加密保障您的聊天安全
+
+
+
+ +
+
实时通讯,消息毫秒级送达
+
+
+
+ +
+
高性能服务,流畅聊天体验
+
+
+
+ +
+ + +
+
账号登录
+
注册账号
+
+ +
+
+ + +
+
+ +
+ + +
+
+ + + +
+
+
或使用其他方式
+
+
+ + + +
+ 没有账号?立即注册 +
+
+ + + +
+
+
+ + + + diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php index 2a60d345..cc60eba8 100644 --- a/resources/views/welcome.blade.php +++ b/resources/views/welcome.blade.php @@ -3,7 +3,7 @@ - Nailao云 - 暗色主题聊天室 + 奶酪云 - 暗色主题聊天室
-

Nailao云聊天室

+

奶酪云聊天室

安全通讯 · 暗色主题 · 极致体验

@@ -526,6 +597,19 @@
+ +
+
+ +
+
+ +
+
+ +
+
+
@@ -547,12 +631,18 @@ // 当前用户信息 let currentUser = { id: '', - name: '' + name: '', + avatarColor: '#6a55fa' // 新增用户头像颜色属性 }; + // 为不同用户生成不同颜色的头像 + const avatarColors = [ + '#6a55fa', '#f87171', '#4ade80', '#fbbf24', '#60a5fa', '#c084fc', '#fb923c' + ]; + // WebSocket连接 let socket = null; - const serverUrl = "ws://t-ws.nailaoyun.cn/ws/"; + const serverUrl = "ws://t-ws.奶酪yun.cn/ws/"; // const serverUrl = "ws://127.0.0.1:18282"; // DOM元素引用 @@ -573,6 +663,9 @@ const onlineCount = document.getElementById('online-count'); const emojiBtn = document.getElementById('emoji-btn'); const emojiPicker = document.getElementById('emoji-picker'); + const imageBtn = document.getElementById('image-btn'); + const voiceBtn = document.getElementById('voice-btn'); + const attachBtn = document.getElementById('attach-btn'); // 登录时清除本地缓存 function clearStoredCredentials() { @@ -612,8 +705,13 @@ currentUser.id = userId; currentUser.name = userName; + // 为用户生成头像颜色 + const randomIndex = Math.floor(Math.random() * avatarColors.length); + currentUser.avatarColor = avatarColors[randomIndex]; + // 更新用户UI userAvatar.textContent = userName.charAt(0).toUpperCase(); + userAvatar.style.background = currentUser.avatarColor; currentUsername.textContent = `${userName} 的聊天`; // 隐藏登录页,显示聊天页 @@ -637,7 +735,8 @@ socket.send(JSON.stringify({ type: 'login', userId: currentUser.id, - userName: currentUser.name + userName: currentUser.name, + avatarColor: currentUser.avatarColor })); }; @@ -687,6 +786,7 @@ addMessage({ userId: message.userId, name: message.userName, + avatarColor: message.avatarColor || avatarColors[Math.floor(Math.random() * avatarColors.length)], text: message.content, timestamp: new Date(message.timestamp), type: message.userId === currentUser.id ? 'sent' : 'received' @@ -711,6 +811,7 @@ type: 'chat', userId: currentUser.id, userName: currentUser.name, + avatarColor: currentUser.avatarColor, content: text, timestamp: Date.now() }; @@ -722,6 +823,7 @@ addMessage({ userId: currentUser.id, name: currentUser.name, + avatarColor: currentUser.avatarColor, text: text, timestamp: new Date(), type: 'sent' @@ -766,28 +868,33 @@ scrollToBottom(); } - // 添加聊天消息到UI + // 添加聊天消息到UI(优化后的结构) function addMessage(msg) { const noMessages = messagesContainer.querySelector('.no-messages'); if (noMessages) noMessages.remove(); - const messageElement = document.createElement('div'); - messageElement.className = `message ${msg.type}`; + const messageContainer = document.createElement('div'); + messageContainer.className = `message-container ${msg.type}`; // 格式化时间 const hours = msg.timestamp.getHours().toString().padStart(2, '0'); const minutes = msg.timestamp.getMinutes().toString().padStart(2, '0'); const timeString = `${hours}:${minutes}`; - messageElement.innerHTML = ` -
- ${msg.name} + messageContainer.innerHTML = ` +
${msg.name.charAt(0).toUpperCase()}
+
+
${msg.name}
+
+
${escapeHtml(msg.text)}
+
+
${timeString}
-
${escapeHtml(msg.text)}
- `; +
+ `; - messagesContainer.appendChild(messageElement); + messagesContainer.appendChild(messageContainer); scrollToBottom(); } @@ -796,7 +903,6 @@ userListContainer.innerHTML = ''; onlineCount.textContent = `(${users.length})`; - console.log(users, 'ssssssssssssss') if (users.length === 0) { userListContainer.innerHTML = '
暂无在线用户
'; return; @@ -806,7 +912,7 @@ const currentUserItem = document.createElement('div'); currentUserItem.className = 'user-item active'; currentUserItem.innerHTML = ` -
${currentUser.name.charAt(0).toUpperCase()}
+
${currentUser.name.charAt(0).toUpperCase()}
${currentUser.name} (我)
`; @@ -814,16 +920,17 @@ // 添加其他用户 users.filter(user => user.id != currentUser.id).forEach(user => { + const avatarColor = user.avatarColor || avatarColors[Math.floor(Math.random() * avatarColors.length)]; + const userItem = document.createElement('div'); userItem.className = 'user-item'; userItem.innerHTML = ` -
${user.name.charAt(0).toUpperCase()}
+
${user.name.charAt(0).toUpperCase()}
${user.name}
`; userListContainer.appendChild(userItem); }); - // 插入到user-list-container } // 初始化Emoji选择器 @@ -881,6 +988,28 @@ location.reload(); } + // 语音录制功能 + function handleVoiceRecording() { + if (!voiceBtn.classList.contains('recording')) { + // 开始录制 + voiceBtn.classList.add('recording'); + voiceBtn.innerHTML = ''; + document.getElementById('voice-btn').style.backgroundColor = 'rgba(248, 113, 113, 0.2)'; + + // 这里应该添加实际录制逻辑 + setTimeout(() => { + // 模拟完成录制 + handleVoiceRecordingEnd(); + }, 3000); + } + } + + function handleVoiceRecordingEnd() { + voiceBtn.classList.remove('recording'); + voiceBtn.innerHTML = ''; + document.getElementById('voice-btn').style.backgroundColor = ''; + } + // 事件监听 document.addEventListener('DOMContentLoaded', () => { initializePage(); @@ -915,6 +1044,19 @@ // 退出登录 logoutBtn.addEventListener('click', handleLogout); + + // 图片按钮功能 + imageBtn.addEventListener('click', () => { + alert('图片上传功能已准备就绪'); + }); + + // 语音按钮功能 + voiceBtn.addEventListener('click', handleVoiceRecording); + + // 附件按钮功能 + attachBtn.addEventListener('click', () => { + alert('附件上传功能已准备就绪'); + }); }); diff --git a/routes/api.php b/routes/api.php new file mode 100644 index 00000000..2ec05328 --- /dev/null +++ b/routes/api.php @@ -0,0 +1,26 @@ + '', +], function () { + cc_auto_route_register([ + 'auth' => \App\Http\Controllers\AuthController::class + ]); +}); +Route::group([ + 'prefix' => '', +], function () { + cc_auto_route_register([ + 'auth' => \App\Http\Controllers\UserController::class + ]); +}); + +Route::post('/b', function () { + $userId = request()->post('user_id'); + $clientId = request()->post('client_id'); + \App\Services\GatewayWorker\GatewayClientService::getInstance()->init()->bindUser($clientId, $userId); + return jok('绑定成功'); +}); + diff --git a/routes/web.php b/routes/web.php index 42e6f3e8..e2e4b73c 100644 --- a/routes/web.php +++ b/routes/web.php @@ -3,7 +3,12 @@ use Illuminate\Support\Facades\Route; Route::get('/', function () { - return view('welcome'); +// return view('welcome'); + return view('chat'); +}); +Route::get('/login', function () { +// return view('welcome'); + return view('login'); }); Route::post('/b', function () { $userId = request()->post('user_id');