251 Commits

Author SHA1 Message Date
632a4240c4 功能:禁用词管理支持批量添加
- 新增 ForbiddenUsernameController::batchStore()
  支持换行、逗号、中文逗号、空格多种分隔格式
  自动去重、跳过已存在词语、忽略超长词
  返回成功数/跳过数详细提示
- 新增路由 POST /admin/forbidden-usernames/batch
- View 新增卡片加「单个/批量」两 Tab 切换
  批量 Tab 使用 textarea 多行输入
2026-03-01 14:04:28 +08:00
fc495ccceb 功能:禁用用户名管理(永久禁词列表)
数据库:
- 新增迁移 username_blacklist 表加 type/reason 列
  type: temp(改名30天保留)| permanent(管理员永久禁用)
  reason: 禁用原因备注(最长100字符)

核心逻辑:
- UsernameBlacklist::isBlocked() 同时拦截两种类型
  也包含 isReserved() 兼容旧调用
  增加 scopePermanent()/scopeTemp() 查询作用域
- AuthController 注册时加 isBlocked() 拦截
  禁词/保留期内均不可注册
- ShopService::useRenameCard() 已有 isReserved() 调用
  因已改用 isBlocked() 别名,无需修改

后台:
- ForbiddenUsernameController:index/store/update/destroy
- 路由:/admin/forbidden-usernames(chat.site_owner 中间件)
- 视图:admin/forbidden-usernames/index.blade.php
  新增表单、关键词搜索、分页、行内编辑原因、删除
- 侧边栏加「🚫 禁用用户名」入口(仅站长可见)
2026-03-01 14:00:38 +08:00
4ced484419 功能:好友列表面板
后端(FriendController::index):
- 返回 sub_time 添加时间
- 新增 pending 列表(对方加了我但我未回加)
  包含用户信息 + added_at(对方添加我的时间)

前端(toolbar.blade.php):
- 工具栏顶部加「好友」按钮(openFriendPanel)
- 好友弹窗面板(#friend-panel):
  ① 搜索栏:输入用户名 Enter/按钮添加好友
  ② 「我关注的好友」列表:头像/用户名/互相徽章/
     添加时间/删除按钮
  ③ 「对方已加我,待我回加」列表:头像/用户名/
     对方添加时间/回加按钮
  ④ 面板顶部提示区(成功/失败消息)
- 所有添加/删除调用与双击用户卡片完全相同的接口
  (/friend/{username}/add、/friend/{username}/remove)
2026-03-01 13:38:30 +08:00
2947f0f741 功能:用户列表增加在线状态列,支持点击排序
- UserManagerController 注入 ChatStateService,从 Redis 聚合
  所有活跃房间在线用户名(跨房间去重)
- 排序白名单加入 'online',在线排序用 orderByRaw CASE WHEN 虚拟列
  desc = 在线用户优先显示,asc = 离线用户优先
- 视图表头加「在线 ↕」可排序列(绿色高亮箭头)
- 每行显示绿色实心点+「在线」/灰点+「离线」小徽章
- my-duty-logs 分页已有 paginate(30)+withQueryString+links(),无需改动
2026-03-01 12:54:34 +08:00
855f169516 功能:后台「我的履职记录」页面
- 侧边栏「我的履职记录」链接,位于「任命管理」上方
- 路由:GET /admin/my-duty-logs → appointments.my-duty-logs
- 控制器:AppointmentController::myDutyLogs()
  支持按操作类型、日期范围筛选,分页,withQueryString()
- 视图:admin/appointments/my-duty-logs.blade.php
  顶部 6 格汇总统计(奖励/踢出/禁言/警告/任命/撤职)
  每张卡片可点击快速按类型筛选
  表格显示:操作时间、类型 Badge、操作对象、所属部门·职务、金币金额、备注
2026-03-01 12:22:13 +08:00
f4de31f92b 优化:奖励消息发送者显示「部门·职务」
$positionName 由单一职务名改为「部门名 · 职务名」格式,
例如:「生产部 · 系长」,无部门时退化为仅显示职务名,
超管保持「超级管理员」不变。
公告文案、私信、Toast 通知均同步更新。
2026-03-01 12:17:16 +08:00
3d7b86f06d 功能:奖励发放聊天室公告 + 右下角 Toast 通知卡片
后端(AdminCommandController::reward):
- 新增聊天室公开公告消息(系统公告,所有在场用户可见)
- 接收者私信附带 toast_notification 字段触发前端小卡片
- 公告文案:「🪙 [职务人] 向 [目标] 发放了 [N] 枚奖励金币!」

前端:
- 新建 chat/partials/toast-notification.blade.php:
  全局右下角 Toast 组件,window.chatToast.show() API
  支持 title/message/icon/color/duration/action 配置
  多条 Toast 从右下角向上堆叠,独立计时、独立关闭
- chat:message 事件监听中检测 toast_notification 字段,
  自动弹出右下角通知卡片(仅接收方可见)
- showFriendToast 迁移至 window.chatToast.show(),
  删除 80 行旧实现,代码量净减
- frame.blade.php 引入新 partial

DEVELOPMENT.md:
- 新增 §7.9 chatToast 完整文档(API、使用场景、迁移说明)
- 原 chatBanner 章节编号改为 §7.10
2026-03-01 12:15:18 +08:00
4ba5a88fc2 优化:奖励弹窗加宽+4列额度+最近10条记录+确认按钮醒目
- 弹窗宽度 320→520px(max-width:95vw 自适应)
- 额度四格改为一行4列(单次上限/单日上限/今日已发/剩余额度)
- 确认按钮改为橙红渐变+投影,视觉更突出
- 输入框下方显示最近10条发放记录(目标/金额/时间)
- 发放成功后实时在历史列表头部插入新纪录
- rewardQuota 接口统一返回 recent_rewards(最近10条)
2026-03-01 11:55:29 +08:00
21cabb08c9 功能:奖励金币改为独立弹窗(展示额度信息)
- 点击「送金币」按钮打开独立弹窗,不再内联在用户名片中
- 弹窗展示 4 格额度信息:单次上限、单日上限、今日已发、剩余额度
- 新增 GET /command/reward-quota 接口(rewardQuota 方法)
  返回当前操作人实时额度,超管返回全部不限
- 发放成功后页面内实时更新今日已发/剩余额度,无需刷新
- 移除原内联奖励面板,action 改为调用全局 openRewardModal()
2026-03-01 11:50:12 +08:00
3d30d7e811 功能:id=1 超管无需职务即可发放奖励金币
前端(frame.blade.php):
- Auth::id()===1 时 myMaxReward=-1(不限),送金币按钮始终显示

后端(AdminCommandController::reward):
- isSuperAdmin=true 时跳过职务检查和①②③④限额校验
- 全局接收次数⑤对超管同样生效(防止刷奖励)
- 履职记录 user_position_id 允许 null(超管无职务时)
- 发放备注改用 positionName 变量(超管显示「超级管理员」)

顺带修复:②操作人单日累计统计之前误查 target_user_id,
已改为正确的 user_id(操作人自己今日已发总额)
2026-03-01 11:43:51 +08:00
89d93c92ed 功能:职务列表内联编辑 + 全局奖励配置自动保存
职务列表三列内联编辑(失焦/回车自动保存,无需打开编辑弹窗):
- 人数上限:PATCH max_persons
- 单次上限:PATCH max_reward
- 单日上限:PATCH daily_reward_limit
保存成功显示短暂绿色 ✓,失败显示红色错误提示

全局奖励接收次数配置改为 AJAX 自动保存,失焦/回车触发,
无需保存按钮(原表单已移除)

新增接口:
- PATCH /admin/positions/{position}/patch(quickPatch)
- POST  /admin/positions/reward-config(saveRewardConfig,兼容 JSON + 重定向)
2026-03-01 11:28:15 +08:00
baaa7087b0 功能:全局奖励接收次数上限(职务管理页配置)
新增全局 sysparam 配置 reward_recipient_daily_max:
- 控制每位用户单日内从所有职务持有者处累计接收奖励的最高次数
- 0 = 不限制

后端变更:
- PositionController::saveRewardConfig() 保存配置
- POST admin/positions/reward-config 路由
- AdminCommandController::reward() 新增第④层校验:
  全局次数上限(优先级低于职务级别的 recipient_daily_limit)

视图变更:
- 职务管理页顶部加橙色配置卡片(行内表单,即改即存)
- 显示当前全局配置值
2026-03-01 11:22:02 +08:00
a145c6fc0a 修复+改进:职务奖励次数上限和后台列表展示
修复:
- recipient_daily_limit 统计逻辑修正:移除 user_id 过滤,
  改为统计今日所有职务持有者对同一接收者的累计发放次数
  (上限含义:该用户今日最多从所有职务人员处收到 N 次奖励)

改进:
- 后台职务列表新增「单日上限」列显示 daily_reward_limit
- 「奖励上限」列改名为「单次上限」更准确
- 两列均支持 null(不限)/ 0(禁止)/ 数值 三种状态区分显示
2026-03-01 11:16:22 +08:00
ff57afe388 功能:职务奖励金币发放系统
数据库:
- positions 新增 daily_reward_limit(单日累计上限)
- positions 新增 recipient_daily_limit(同一接收者每日次数上限)

后端:
- CurrencySource::POSITION_REWARD 新枚举值
- AdminCommandController::reward() 三层限额校验
  ① 单次上限 ② 单日累计上限 ③ 同一接收者每日次数
  写履职记录(PositionAuthorityLog)+ UserCurrencyService
  聊天室悄悄话通知接收者
- POST /command/reward 路由注册

前端(user-actions.blade.php):
- 名片按钮行 2+1 布局(加好友/送礼物/送金币)
- 送金币仅在 myMaxReward>0 时显示(职务持有者)
- 内联奖励金币面板:金额输入 + 确认发放 + 说明文字
- sendReward() 前端校验 + API 调用 + chatDialog 反馈

后台(positions/index):
- 编辑表单新增两个奖励限额字段
- PositionController 验证规则同步更新
2026-03-01 11:09:29 +08:00
476499832f 功能:勤务台榜单新增管理操作次数 + 奖励金币次数统计
DutyHallController:
- 新增 position_authority_logs 关联查询
- 统计管理操作次数(warn/kick/mute/banip/other,排除人事任免)
- 统计奖励金币次数及累计金额(action_type=reward)
- 时间范围统一过滤(日/周/月/总)
- 合并两表数据到榜单 Collection

duty-hall/index.blade.php:
- 表格扩展为 6 列:名次、成员、在线时长、登录次数、管理操作、奖励金币
- 奖励金币栏 hover 显示次数+总金额 tooltip
- 移动端显示紧凑卡片(管理/奖励只在 >0 时显示)
- 底部图例说明各列含义
2026-03-01 10:51:48 +08:00
7bae5e56ff 修复:私有频道改用数字 ID,解决中文用户名导致 Pusher 频道名非法
错误原因:Pusher 频道名只允许 [a-zA-Z0-9_\-=@,.],
中文用户名(如「超级舞魅」)用于 private-user.{username} 导致
PusherException: Invalid channel name。

修复方案(改用数字 ID):
- FriendAdded/FriendRemoved 构造加 toUserId 参数
- broadcastOn() 改为 PrivateChannel('user.' . $toUserId)
- FriendController 传入 $target->id / $targetUser->id
- channels.php 鉴权改为 'user.{id}',核对 $user->id 数字相等
- frame.blade.php chatContext 加 userId
- scripts.blade.php Echo.private 改用 userId 订阅
2026-03-01 01:41:04 +08:00
5c53b8cf2f 功能:window.chatBanner 全局大卡片公共组件
前端:
- window.chatBanner.show(options) 全局 API,完全自定义:
  icon/title/name/body/sub/gradient/titleColor/autoClose/buttons
- window.chatBanner.close(id) 关闭指定 banner
- showFriendBanner / showAppointmentBanner 均改用 chatBanner 实现
- setupBannerNotification() 监听私有+房间频道的 BannerNotification 事件

后端:
- BannerNotification 事件(ShouldBroadcastNow),支持 user/room 双目标
- BannerBroadcastController(仅超级管理员路由,三层中间件保护)
- 内容字段 strip_tags 净化防 XSS,按钮 action 白名单校验

安全:
- window.chatBanner.show() 被人控制台调用只影响自己,无法推给他人
- HTTP 入口 POST /admin/banner/broadcast 仅超管可访问
2026-03-01 01:28:23 +08:00
0f0691d037 修复:FriendAdded/FriendRemoved 改为 ShouldBroadcastNow
ShouldBroadcast 走队列(异步),不保证及时广播;
ShouldBroadcastNow 不走队列,与 MessageSent 一致,立即推送到 Reverb。
这是大卡弹窗收不到的真实原因。
2026-03-01 01:21:33 +08:00
7985a9b0d7 修复:FriendAdded/FriendRemoved 加 broadcastAs() 修复私有频道事件名不匹配
前端 .listen('.FriendAdded') 匹配的是短名 FriendAdded,
但默认广播名是 App\Events\FriendAdded(全类名),导致监听器永远不触发。
加 broadcastAs() 返回短名后两端匹配,弹窗可正常弹出。
2026-03-01 01:13:50 +08:00
d60a225368 修复:好友悄悄话链接 href 出现字面 \'#\' 导致404问题
PHP 双引号字符串里单引号不需要反斜杠转义,
\'#\' 会原样输出 \'#\' 而非 '#',导致 href 跳转到错误 URL。
改为直接写 '#' 即可。
2026-03-01 01:05:47 +08:00
212f7a0096 功能:好友悄悄话内嵌快捷操作链接
后端:
- notifyOnlineUser 生成带内联 <a> 标签的内容
- added 未互相 → 嵌入 ' 回加好友' 链接
- removed 互相  → 嵌入 '🗑️ 同步移除' 链接
- 链接调用全局 quickFriendAction(act, username, el)

前端:
- 新增 window.quickFriendAction() 全局函数
- 防重复点击(dataset.done 标记)
- 成功后更新链接文字 ' 已回加' / ' 已移除',不刷新页面
2026-03-01 01:03:10 +08:00
cc16f89bbe 修复:好友悄悄话文案根据互相状态精确区分
- notifyOnlineUser 加 $mutual 参数
- added + mutual=false → '但你还没有添加对方为好友'
- added + mutual=true  → '你们现在互为好友 🎉'
- removed + mutual=true  → '你的好友列表中仍保留对方'
- removed + mutual=false → '已将你从他的好友列表移除'
- 删除操作悄悄话改为灰色 (#6b7280),语义更准确
2026-03-01 00:59:10 +08:00
3c2038e8fe 优化:好友通知弹窗根据互相状态显示不同内容
FriendAdded 事件:
- 新增 hasAddedBack 字段(B 是否已回加 A)
- Toast:已互相好友 → '你们现在互为好友 🎉'
- Toast:未回加 → '但你还没有添加对方为好友' + [ 回加] 一键操作按钮

FriendRemoved 事件:
- 新增 hadAddedBack 字段(之前是否互相好友)
- Toast:之前互相好友 → 提示 + [🗑️ 同步移除] 一键操作按钮
- Toast:单向好友 → 简单通知,无操作按钮

Toast 改进:
- 右上角 × 关闭按钮
- 快捷操作按钮支持 fetch 直接请求
- 完成后显示结果并自动关闭,延时改为 8 秒
2026-03-01 00:54:10 +08:00
700ab9def4 feat: 好友系统全实现
后端:
- FriendController:add/remove/status/index 四个接口
- FriendAdded / FriendRemoved 广播事件(私有频道)
- channels.php 注册 user.{username} 私有频道鉴权
- routes/web.php 注册好友路由
- ChatController::init() 修复 DutyLog 在 return 后执行的 bug
- ChatController::notifyFriendsOnline() 上线时悄悄话通知好友

前端:
- user-actions:写私信 → 加好友/删好友按钮(动态状态)
- toggleFriend() 方法 + fetchUser 后加载好友状态
- scripts:监听私有频道 FriendAdded/FriendRemoved
- showFriendToast() 右下角浮窗通知(5秒自动消失)
- global-dialog 加 fdSlideIn 动画
2026-03-01 00:48:51 +08:00
94414057e6 修复:User 模型 fillable 缺少 in_time/out_time,导致进房时间静默写入失败 2026-03-01 00:10:44 +08:00
76fd17c727 功能:存点时自动同步在职用户勤务日志
- heartbeat 手动存点:调用 tickDutyLog()
- AutoSaveExp 自动存点:调用 tickDutyLog()
- 逻辑:今日已有开放日志则刷新 duration_seconds,无则新建(login_at 取 in_time 进房时间)
- 修复:TIMESTAMPDIFF 结果用 GREATEST(0, ...) 防 unsigned 溢出
- 修复:database.php MySQL 连接加 timezone=+08:00,与 PHP Asia/Shanghai 时区对齐
2026-03-01 00:04:59 +08:00
5f30220609 feat: 任命/撤销通知系统 + 用户名片UI优化
- 任命/撤销事件增加 type 字段区分类型
- 任命:全屏礼花 + 紫色弹窗 + 紫色系统消息
- 撤销:灰色弹窗 + 灰色系统消息,无礼花
- 消息分发:操作者/被操作者显示在私聊面板,其他人显示在公屏
- 系统消息加随机鼓励语(各5条轮换)
- ChatStateService 修复 Redis key 前缀扫描问题(getAllActiveRoomIds)
- 用户名片折叠优化:管理员视野、职务履历均可折叠
- 管理操作 + 职务操作合并为「🔧 管理操作」折叠区
- 悄悄话改为「🎁 送礼物」按钮,礼物面板内联展开
2026-02-28 23:44:38 +08:00
7643740eda 功能:今日风云榜独立页 /leaderboard/today,导航新增「今日榜」按钮 2026-02-28 13:50:51 +08:00
72d23af335 功能:ChatController 新人礼包 6666 金币接入积分流水,记录 newbie_bonus 来源 2026-02-28 13:34:40 +08:00
0c5e218aa8 功能:新增用户积分流水系统
- 新建 user_currency_logs 流水表 (Migration)
- App\Enums\CurrencySource 来源枚举(可扩展)
- App\Models\UserCurrencyLog 流水模型
- App\Services\UserCurrencyService 统一积分变更服务
- FishingController:抛竿/收竿接入流水记录
- AutoSaveExp:自动存点接入流水记录
- Admin/UserManagerController:管理员调整接入流水记录
- LeaderboardController:新增今日三榜(经验/金币/魅力)+ 个人流水日志页
- Admin/CurrencyStatsController:后台活动统计页
- views:新增个人日志页、后台统计页;排行榜新增今日榜数据传递
- routes:新增个人日志路由 /my/currency-logs、后台路由 /admin/currency-stats
2026-02-28 12:49:26 +08:00
ffe35c048d 修复:历史消息服务端过滤,只加载与当前用户相关的记录,避免他人私聊和系统通知混入包厢窗 2026-02-28 11:54:29 +08:00
9a98bdfbe6 修复:聊天室初次加载时附带历史消息,解决因网络延迟错失入场欢迎语的问题 2026-02-28 11:17:09 +08:00
7bbc4c18d7 优化:AI聊天机器人知道对方的名字,并且连接超时不再抛出底层的cURL长代码错误 2026-02-27 17:50:08 +08:00
4ef95eaa27 新增:新人首次入住聊天室大礼包自动发放功能(6666金币 + 满场烟花 + 公屏欢迎) 2026-02-27 17:21:33 +08:00
3ad67a1610 优化:修改单次特效卡的公屏广播文案,避免让大家误以为是赠送了道具卡实体 2026-02-27 17:00:26 +08:00
43956d286e 修复:礼物系统消息字段名改为 from_user/to_user/sent_at 与前端 appendMessage() 匹配,触发金色边框样式 2026-02-27 16:30:41 +08:00
157aee3812 修复:confirmGift null错误(先保存item再关弹框);MessageSent改为ShouldBroadcastNow立即广播;修复route()引号冲突 2026-02-27 16:26:16 +08:00
6a8ba4fbc8 功能:单次特效卡支持赠送——送礼弹框、广播给指定用户/全员、公屏系统消息、购买后关闭商店展示特效 2026-02-27 16:19:21 +08:00
7fb86bfe21 Feat: 商店功能完整实现(单次特效卡888/周卡8888/改名卡5000,含购买、周卡覆盖、改名黑名单) 2026-02-27 15:57:12 +08:00
b366c9888f Feat: 后台用户列表增加金币/魅力列,表头支持点击排序(等级/经验/金币/魅力) 2026-02-27 15:31:29 +08:00
4668c163aa Feat: 管理员进入聊天室自动触发烟花+公屏欢迎公告 2026-02-27 14:34:04 +08:00
4da2d19b1f Feat: 新增下雪特效,加强烟花/下雨在浅色背景的显色(发光粒子+深色雨线) 2026-02-27 14:22:13 +08:00
709e0d4975 Feat: 实现全屏特效系统(烟花/下雨/雷电),管理员一键触发全房间广播 2026-02-27 14:14:35 +08:00
4b231c19f7 Fix: 升级播报改为金色左边框轻量样式,与站长公告红框区分开 2026-02-27 13:44:24 +08:00
caecceba1b Fix: 系统存点通知改回悄悄话私信,避免多人刷屏;前端单独渲染为绿色通知条无头像 2026-02-27 12:53:30 +08:00
638bc9deda Feat: 优化自动存点通知样式,系统消息不显示头像,改为绿色左边框简洁条形 2026-02-27 12:51:29 +08:00
eb7bc58417 Fix: 彻底抛弃Redis SCAN方案,改用Room::pluck+hkeys精准读取在线用户,解决predis前缀导致扫描失败的问题 2026-02-27 12:48:23 +08:00
2bbb13e85b Fix: 用原始Redis客户端绕过自动前缀,解决hkeys双重前缀找不到用户问题 2026-02-27 12:42:45 +08:00
36fc073971 Fix: 修正Redis扫描键名前缀不匹配问题,改为*room:*:users通配前缀模式 2026-02-27 12:41:20 +08:00
2044feec12 Feat: 新增定时自动存点指令,每5分钟为在线用户发放经验金币并推送系统通知 2026-02-27 12:39:23 +08:00