Files
chatroom/resources/views/chat/frame.blade.php
lkddi 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

159 lines
7.3 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{--
文件功能聊天室主界面框架frame 页面)
全屏沉浸式布局,不使用统一 layout
CSS 抽取到 /public/css/chat.css
JS 抽取到 chat.partials.scripts Blade 模板
@author ChatRoom Laravel
@version 1.0.0
--}}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $room->name ?? '聊天室' }} - 飘落流星</title>
<meta name="csrf-token" content="{{ csrf_token() }}">
@php
// 从 sysparam 读取权限等级配置
$levelWarn = (int) \App\Models\Sysparam::getValue('level_warn', '5');
$levelKick = (int) \App\Models\Sysparam::getValue('level_kick', '10');
$levelMute = (int) \App\Models\Sysparam::getValue('level_mute', '8');
$levelBan = (int) \App\Models\Sysparam::getValue('level_ban', '12');
$levelBanip = (int) \App\Models\Sysparam::getValue('level_banip', '14');
$levelFreeze = (int) \App\Models\Sysparam::getValue('level_freeze', '14');
$superLevel = (int) \App\Models\Sysparam::getValue('superlevel', '100');
$myLevel = Auth::user()->user_level;
@endphp
<script>
window.chatContext = {
roomId: {{ $room->id }},
userId: {{ $user->id }},
username: "{{ $user->username }}",
userLevel: {{ $user->user_level }},
superLevel: {{ $superLevel }},
levelKick: {{ $levelKick }},
levelMute: {{ $levelMute }},
levelBan: {{ $levelBan }},
levelBanip: {{ $levelBanip }},
sendUrl: "{{ route('chat.send', $room->id) }}",
leaveUrl: "{{ route('chat.leave', $room->id) }}",
heartbeatUrl: "{{ route('chat.heartbeat', $room->id) }}",
fishCastUrl: "{{ route('fishing.cast', $room->id) }}",
fishReelUrl: "{{ route('fishing.reel', $room->id) }}",
chatBotUrl: "{{ route('chatbot.chat') }}",
chatBotClearUrl: "{{ route('chatbot.clear') }}",
chatBotEnabled: {{ \App\Models\Sysparam::getValue('chatbot_enabled', '0') === '1' ? 'true' : 'false' }},
hasPosition: {{ Auth::user()->activePosition || Auth::user()->user_level >= $superLevel ? 'true' : 'false' }},
myMaxReward: {{ Auth::user()->activePosition?->position?->max_reward ?? 0 }},
appointPositionsUrl: "{{ route('chat.appoint.positions') }}",
appointUrl: "{{ route('chat.appoint.appoint') }}",
revokeUrl: "{{ route('chat.appoint.revoke') }}",
rewardUrl: "{{ route('command.reward') }}"
};
</script>
@vite(['resources/css/app.css', 'resources/js/app.js', 'resources/js/chat.js'])
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<link rel="stylesheet" href="/css/chat.css">
</head>
<body>
<div class="chat-layout">
{{-- ═══════════ 左侧主区域 ═══════════ --}}
<div class="chat-left">
{{-- 顶部标题栏 + 公告滚动条(独立文件维护) --}}
@include('chat.partials.header')
{{-- 消息窗格(双窗格,默认只显示 say1 --}}
<div class="message-panes" id="message-panes">
{{-- 主消息窗 --}}
<div class="message-pane say1" id="chat-messages-container">
<div class="msg-line">
<span style="color: #cc0000; font-weight: bold;">【公众窗口】</span>显示公众的发言!
<span class="msg-time">({{ now()->format('H:i:s') }})</span><br>
<span
style="color: #000099;">{{ $room->name }}{{ $room->description ?? '欢迎光临!畅所欲言,文明聊天。' }}</span>
</div>
</div>
{{-- 副消息窗(包厢窗) --}}
<div class="message-pane say2" id="chat-messages-container2">
<div class="msg-line">
<span style="color: #cc0000; font-weight: bold;">【包厢窗口】</span>显示包厢名单中聊友的发言!
<span class="msg-time">({{ now()->format('H:i:s') }})</span>
</div>
</div>
</div>
{{-- 底部输入工具栏(独立文件维护) --}}
@include('chat.partials.input-bar')
</div>
{{-- ═══════════ 竖向工具条(独立文件维护) ═══════════ --}}
@include('chat.partials.toolbar')
{{-- ═══════════ 右侧用户面板(独立文件维护) ═══════════ --}}
@include('chat.partials.right-panel')
</div>
{{-- ═══════════ 全局自定义弹窗(替代原生 alert/confirm全页面可用 ═══════════ --}}
@include('chat.partials.global-dialog')
{{-- ═══════════ 聊天室交互脚本(独立文件维护) ═══════════ --}}
@include('chat.partials.user-actions')
{{-- 全屏特效系统:管理员烟花/下雨/雷电/下雪 --}}
<script src="/js/effects/effect-manager.js"></script>
<script src="/js/effects/fireworks.js"></script>
<script src="/js/effects/rain.js"></script>
<script src="/js/effects/lightning.js"></script>
<script src="/js/effects/snow.js"></script>
@include('chat.partials.scripts')
{{-- 页面初始加载时,渲染自带的历史记录(解决入场欢迎语错过断网的问题) --}}
@if (!empty($historyMessages))
<script>
document.addEventListener('DOMContentLoaded', () => {
const historyMsgs = @json($historyMessages);
const clearId = parseInt(localStorage.getItem(`local_clear_msg_id_{{ $room->id }}`) || '0', 10);
if (historyMsgs && historyMsgs.length > 0) {
// 全局函数 appendMessage 在 scripts.blade.php 中定义
historyMsgs.forEach(msg => {
// 如果开启了本地清屏,之前的历史记录不再显示
if (msg.id > clearId) {
if (typeof window.appendMessage === 'function') {
window.appendMessage(msg);
}
}
});
}
});
</script>
@endif
{{-- 进房特效自动播放:新人烟花礼包 / 周卡特效 --}}
@if (!empty($newbieEffect) || !empty($weekEffect))
<script>
/**
* 延迟1秒待页面完成初始化后自动播放进房附带的特效
* 优先级:如果有新人礼包特效,优先播放新人大礼包;如果没有,再播放周卡特效
*/
setTimeout(() => {
if (window.EffectManager) {
@if (!empty($newbieEffect))
window.EffectManager.play('{{ $newbieEffect }}');
@elseif (!empty($weekEffect))
window.EffectManager.play('{{ $weekEffect }}');
@endif
}
}, 1000);
</script>
@endif
</body>
</html>