feat: 聊天室手机端自适应
- 新增 mobile-drawer.blade.php:手机端浮动按钮 + 工具菜单抽屉 + 名单抽屉(独立维护) - frame.blade.php:手机端代码改为 @include 引入 - chat.css:添加 @media (max-width: 640px) 响应式样式 - 隐藏桌面端工具条和右侧名单面板 - 浮动按钮样式(位于屏幕中间偏右) - 抽屉组件从顶部向下展开 - 手机端隐藏房间介绍、输入栏动作/字色/字号/禁音/分屏控件 - 现有 modal 弹窗 max-width 自适应修复 - scripts.blade.php:重构 renderUserList 提取 _renderUserListToContainer - 修复代码损坏残留,补回 setAction/scrollToBottom/autoScrollEl
This commit is contained in:
@@ -119,8 +119,12 @@
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ── 动作选择 ──────────────────────────────────────
|
||||
/**
|
||||
* 设置发言动作并聚焦输入框
|
||||
*
|
||||
* @param {string} act 动作名称
|
||||
*/
|
||||
function setAction(act) {
|
||||
document.getElementById('action').value = act;
|
||||
switchTab('users');
|
||||
@@ -136,6 +140,9 @@
|
||||
}
|
||||
|
||||
// ── 滚动到底部 ───────────────────────────────────
|
||||
/**
|
||||
* 将公聊窗口滚动到最新消息(受 autoScroll 开关控制)
|
||||
*/
|
||||
function scrollToBottom() {
|
||||
if (autoScroll) {
|
||||
container.scrollTop = container.scrollHeight;
|
||||
@@ -143,9 +150,16 @@
|
||||
}
|
||||
|
||||
// ── 渲染在线人员列表(支持排序) ──────────────────
|
||||
function renderUserList() {
|
||||
userList.innerHTML = '';
|
||||
toUserSelect.innerHTML = '<option value="大家">大家</option>';
|
||||
/**
|
||||
* 核心渲染函数:将在线用户渲染到指定容器(桌面端名单区和手机端抽屉共用)
|
||||
*
|
||||
* @param {HTMLElement} targetContainer 目标 DOM 容器
|
||||
* @param {string} sortBy 排序方式:'default' | 'name' | 'level'
|
||||
* @param {string} keyword 搜索关键词(小写)
|
||||
*/
|
||||
function _renderUserListToContainer(targetContainer, sortBy, keyword) {
|
||||
if (!targetContainer) return;
|
||||
targetContainer.innerHTML = '';
|
||||
|
||||
// 在列表顶部添加"大家"条目(原版风格)
|
||||
let allDiv = document.createElement('div');
|
||||
@@ -154,7 +168,7 @@
|
||||
allDiv.onclick = () => {
|
||||
toUserSelect.value = '大家';
|
||||
};
|
||||
userList.appendChild(allDiv);
|
||||
targetContainer.appendChild(allDiv);
|
||||
|
||||
// ── AI 小助手(仅当全局开关开启时显示,与普通用户风格一致)──
|
||||
if (window.chatContext.chatBotEnabled) {
|
||||
@@ -168,19 +182,9 @@
|
||||
toUserSelect.value = 'AI小班长';
|
||||
document.getElementById('content').focus();
|
||||
};
|
||||
userList.appendChild(botDiv);
|
||||
|
||||
// 在发言对象下拉框中也添加 AI 小助手
|
||||
let botOption = document.createElement('option');
|
||||
botOption.value = 'AI小班长';
|
||||
botOption.textContent = '🤖 AI小班长';
|
||||
toUserSelect.appendChild(botOption);
|
||||
targetContainer.appendChild(botDiv);
|
||||
}
|
||||
|
||||
// 获取排序方式
|
||||
const sortSelect = document.getElementById('user-sort-select');
|
||||
const sortBy = sortSelect ? sortSelect.value : 'default';
|
||||
|
||||
// 构建用户数组并排序
|
||||
let userArr = [];
|
||||
for (let username in onlineUsers) {
|
||||
@@ -196,21 +200,23 @@
|
||||
userArr.sort((a, b) => (b.user_level || 0) - (a.user_level || 0));
|
||||
}
|
||||
|
||||
let count = userArr.length;
|
||||
|
||||
userArr.forEach(user => {
|
||||
const username = user.username;
|
||||
|
||||
// 搜索过滤
|
||||
if (keyword && !username.toLowerCase().includes(keyword)) return;
|
||||
|
||||
let item = document.createElement('div');
|
||||
item.className = 'user-item';
|
||||
item.dataset.username = username;
|
||||
|
||||
const headface = (user.headface || '1.gif').toLowerCase();
|
||||
const headImgSrc = headface.startsWith('storage/') ? '/' + headface : '/images/headface/' + headface;
|
||||
const headImgSrc = headface.startsWith('storage/') ? '/' + headface : '/images/headface/' +
|
||||
headface;
|
||||
|
||||
// 徽章优先级:职务图标 > 管理员 > VIP
|
||||
let badges = '';
|
||||
if (user.position_icon) {
|
||||
// 有职务:显示职务图标,hover 显示职务名称
|
||||
const posTitle = (user.position_name || '在职') + ' · ' + username;
|
||||
badges +=
|
||||
`<span style="font-size:13px; margin-left:2px;" title="${posTitle}">${user.position_icon}</span>`;
|
||||
@@ -235,23 +241,48 @@
|
||||
};
|
||||
// 双击打开用户名片弹窗(全局统一入口)
|
||||
item.ondblclick = () => openUserCard(username);
|
||||
userList.appendChild(item);
|
||||
targetContainer.appendChild(item);
|
||||
});
|
||||
}
|
||||
|
||||
function renderUserList() {
|
||||
userList.innerHTML = '';
|
||||
toUserSelect.innerHTML = '<option value="大家">大家</option>';
|
||||
|
||||
// 获取排序方式和搜索词
|
||||
const sortSelect = document.getElementById('user-sort-select');
|
||||
const sortBy = sortSelect ? sortSelect.value : 'default';
|
||||
const searchInput = document.getElementById('user-search-input');
|
||||
const keyword = searchInput ? searchInput.value.trim().toLowerCase() : '';
|
||||
|
||||
// 调用核心渲染(桌面端名单容器)
|
||||
_renderUserListToContainer(userList, sortBy, keyword);
|
||||
|
||||
// 重新填充发言对象下拉框(不过滤关键词,始终显示全部用户)
|
||||
toUserSelect.innerHTML = '<option value="大家">大家</option>';
|
||||
if (window.chatContext.chatBotEnabled) {
|
||||
let botOption = document.createElement('option');
|
||||
botOption.value = 'AI小班长';
|
||||
botOption.textContent = '🤖 AI小班长';
|
||||
toUserSelect.appendChild(botOption);
|
||||
}
|
||||
for (let username in onlineUsers) {
|
||||
if (username !== window.chatContext.username) {
|
||||
let option = document.createElement('option');
|
||||
option.value = username;
|
||||
option.textContent = username;
|
||||
toUserSelect.appendChild(option);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const count = Object.keys(onlineUsers).length;
|
||||
onlineCount.innerText = count;
|
||||
onlineCountBottom.innerText = count;
|
||||
const footer = document.getElementById('online-count-footer');
|
||||
if (footer) footer.innerText = count;
|
||||
if (footer) { footer.innerText = count; }
|
||||
|
||||
// 如果有搜索关键词,重新过滤
|
||||
filterUserList();
|
||||
// 派发用户列表更新事件,供手机端抽屉同步
|
||||
window.dispatchEvent(new Event('chatroom:users-updated'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -275,6 +306,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 追加消息到聊天窗格(原版风格:非气泡模式,逐行显示)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user