新增职务权限管理与聊天室管理权限控制
This commit is contained in:
@@ -13,9 +13,14 @@ use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\StoreBaccaratLossCoverEventRequest;
|
||||
use App\Models\BaccaratLossCoverEvent;
|
||||
use App\Services\BaccaratLossCoverService;
|
||||
use App\Services\PositionPermissionService;
|
||||
use App\Support\PositionPermissionRegistry;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* 类功能:处理聊天室顶部快捷入口创建与结束百家乐买单活动。
|
||||
*/
|
||||
class BaccaratLossCoverEventController extends Controller
|
||||
{
|
||||
/**
|
||||
@@ -23,6 +28,7 @@ class BaccaratLossCoverEventController extends Controller
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly BaccaratLossCoverService $lossCoverService,
|
||||
private readonly PositionPermissionService $positionPermissionService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -30,6 +36,13 @@ class BaccaratLossCoverEventController extends Controller
|
||||
*/
|
||||
public function store(StoreBaccaratLossCoverEventRequest $request): JsonResponse
|
||||
{
|
||||
if (! $this->positionPermissionService->hasPermission($request->user(), PositionPermissionRegistry::ROOM_BACCARAT_LOSS_COVER)) {
|
||||
return response()->json([
|
||||
'ok' => false,
|
||||
'message' => '当前职务无权创建买单活动。',
|
||||
], 403);
|
||||
}
|
||||
|
||||
try {
|
||||
$event = $this->lossCoverService->createEvent($request->user(), $request->validated());
|
||||
} catch (\RuntimeException $exception) {
|
||||
@@ -51,6 +64,13 @@ class BaccaratLossCoverEventController extends Controller
|
||||
*/
|
||||
public function close(Request $request, BaccaratLossCoverEvent $event): JsonResponse
|
||||
{
|
||||
if (! $this->positionPermissionService->hasPermission($request->user(), PositionPermissionRegistry::ROOM_BACCARAT_LOSS_COVER)) {
|
||||
return response()->json([
|
||||
'ok' => false,
|
||||
'message' => '当前职务无权结束买单活动。',
|
||||
], 403);
|
||||
}
|
||||
|
||||
$event = $this->lossCoverService->forceCloseEvent($event, $request->user());
|
||||
|
||||
return response()->json([
|
||||
|
||||
@@ -16,10 +16,15 @@ use App\Http\Controllers\Controller;
|
||||
use App\Models\Department;
|
||||
use App\Models\Position;
|
||||
use App\Models\Sysparam;
|
||||
use App\Support\PositionPermissionRegistry;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\View\View;
|
||||
|
||||
/**
|
||||
* 类功能:负责后台职务资料、任命白名单与聊天室权限配置的维护。
|
||||
*/
|
||||
class PositionController extends Controller
|
||||
{
|
||||
/**
|
||||
@@ -29,16 +34,25 @@ class PositionController extends Controller
|
||||
{
|
||||
// 按部门分组展示
|
||||
$departments = Department::with([
|
||||
'positions' => fn ($q) => $q->withCount(['activeUserPositions'])->ordered(),
|
||||
'positions' => fn ($q) => $q->withCount(['activeUserPositions'])->with('appointablePositions')->ordered(),
|
||||
])->ordered()->get();
|
||||
|
||||
// 全部职务(供任命白名单多选框使用)
|
||||
$allPositions = Position::with('department')->orderByDesc('rank')->get();
|
||||
$allPositions = Position::with('department')->ordered()->get();
|
||||
|
||||
// 全局奖励接收次数上限(0 = 不限)
|
||||
$globalRecipientDailyMax = (int) Sysparam::getValue('reward_recipient_daily_max', '0');
|
||||
|
||||
return view('admin.positions.index', compact('departments', 'allPositions', 'globalRecipientDailyMax'));
|
||||
$positionPermissions = PositionPermissionRegistry::groupedDefinitions();
|
||||
$permissionLabels = PositionPermissionRegistry::labelMap();
|
||||
|
||||
return view('admin.positions.index', compact(
|
||||
'departments',
|
||||
'allPositions',
|
||||
'globalRecipientDailyMax',
|
||||
'positionPermissions',
|
||||
'permissionLabels',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,10 +73,13 @@ class PositionController extends Controller
|
||||
'sort_order' => 'required|integer|min:0',
|
||||
'appointable_ids' => 'nullable|array',
|
||||
'appointable_ids.*' => 'exists:positions,id',
|
||||
'permissions' => 'nullable|array',
|
||||
'permissions.*' => ['string', Rule::in(PositionPermissionRegistry::codes())],
|
||||
]);
|
||||
|
||||
$appointableIds = $data['appointable_ids'] ?? [];
|
||||
unset($data['appointable_ids']);
|
||||
$data['permissions'] = array_values(array_unique($data['permissions'] ?? []));
|
||||
|
||||
$position = Position::create($data);
|
||||
|
||||
@@ -147,10 +164,13 @@ class PositionController extends Controller
|
||||
'sort_order' => 'required|integer|min:0',
|
||||
'appointable_ids' => 'nullable|array',
|
||||
'appointable_ids.*' => 'exists:positions,id',
|
||||
'permissions' => 'nullable|array',
|
||||
'permissions.*' => ['string', Rule::in(PositionPermissionRegistry::codes())],
|
||||
]);
|
||||
|
||||
$appointableIds = $data['appointable_ids'] ?? [];
|
||||
unset($data['appointable_ids']);
|
||||
$data['permissions'] = array_values(array_unique($data['permissions'] ?? []));
|
||||
|
||||
$position->update($data);
|
||||
$position->appointablePositions()->sync($appointableIds);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* 文件功能:管理员聊天室实时命令控制器
|
||||
*
|
||||
* 提供管理员在聊天室内对用户执行的管理操作:
|
||||
* 警告(=J)、踢出(=T)、禁言(=B)、冻结(=Y)、查看私信(=S)、站长公屏讲话。
|
||||
* 警告(=J)、踢出(=T)、禁言(=B)、冻结(=Y)、查看私信(=S)、职务公屏讲话。
|
||||
*
|
||||
* 对应原 ASP 文件:DOUSER.ASP / KILLUSER.ASP / LOCKIP.ASP / NEWSAY.ASP
|
||||
*
|
||||
@@ -24,13 +24,18 @@ use App\Models\PositionAuthorityLog;
|
||||
use App\Models\Sysparam;
|
||||
use App\Models\User;
|
||||
use App\Services\ChatStateService;
|
||||
use App\Services\PositionPermissionService;
|
||||
use App\Services\UserCurrencyService;
|
||||
use App\Support\PositionPermissionRegistry;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
/**
|
||||
* 类功能:处理聊天室内的实时管理命令与部分职务奖励操作。
|
||||
*/
|
||||
class AdminCommandController extends Controller
|
||||
{
|
||||
/**
|
||||
@@ -39,6 +44,7 @@ class AdminCommandController extends Controller
|
||||
public function __construct(
|
||||
private readonly ChatStateService $chatState,
|
||||
private readonly UserCurrencyService $currencyService,
|
||||
private readonly PositionPermissionService $positionPermissionService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -347,9 +353,10 @@ class AdminCommandController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* 站长公屏讲话
|
||||
* 聊天室公屏讲话
|
||||
*
|
||||
* 站长发送全聊天室公告,以特殊样式显示。
|
||||
* 拥有 room.public_broadcast 权限的职务可以发送全聊天室公告,
|
||||
* id=1 站长仍然拥有完整兜底权限。
|
||||
*
|
||||
* @param Request $request 请求对象,需包含 content, room_id
|
||||
* @return JsonResponse 操作结果
|
||||
@@ -362,22 +369,21 @@ class AdminCommandController extends Controller
|
||||
]);
|
||||
|
||||
$admin = Auth::user();
|
||||
$superLevel = (int) Sysparam::getValue('superlevel', '100');
|
||||
|
||||
if ($admin->user_level < $superLevel) {
|
||||
return response()->json(['status' => 'error', 'message' => '仅站长可发布公屏讲话'], 403);
|
||||
if (! $this->positionPermissionService->hasPermission($admin, PositionPermissionRegistry::ROOM_PUBLIC_BROADCAST)) {
|
||||
return response()->json(['status' => 'error', 'message' => '当前职务无权发布公屏讲话'], 403);
|
||||
}
|
||||
|
||||
$roomId = $request->input('room_id');
|
||||
$content = $request->input('content');
|
||||
|
||||
// 广播站长公告
|
||||
// 按当前在职职务拼装发布者身份,避免继续显示为固定“站长公告”
|
||||
$publisherLabel = $this->buildAnnouncementPublisherLabel($admin);
|
||||
$msg = [
|
||||
'id' => $this->chatState->nextMessageId($roomId),
|
||||
'room_id' => $roomId,
|
||||
'from_user' => '系统公告',
|
||||
'to_user' => '大家',
|
||||
'content' => "📢 站长 <b>{$admin->username}</b> 讲话:{$content}",
|
||||
'content' => "📢 <b>{$publisherLabel}</b> <b>{$admin->username}</b> 发布公告:{$content}",
|
||||
'is_secret' => false,
|
||||
'font_color' => '#b91c1c',
|
||||
'action' => '',
|
||||
@@ -390,6 +396,28 @@ class AdminCommandController extends Controller
|
||||
return response()->json(['status' => 'success', 'message' => '公告已发送']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成公屏公告发布者身份标签。
|
||||
*
|
||||
* 普通在职用户按“部门+职务”显示;站长无在职职务时保持“站长”标识兜底。
|
||||
*/
|
||||
private function buildAnnouncementPublisherLabel(User $user): string
|
||||
{
|
||||
$position = $user->activePosition?->position;
|
||||
|
||||
if ($position) {
|
||||
$departmentName = (string) ($position->department?->name ?? '');
|
||||
|
||||
return $departmentName.$position->name;
|
||||
}
|
||||
|
||||
if ($user->id === 1) {
|
||||
return '站长';
|
||||
}
|
||||
|
||||
return '管理员';
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理员全员清屏
|
||||
*
|
||||
@@ -407,11 +435,9 @@ class AdminCommandController extends Controller
|
||||
|
||||
$admin = Auth::user();
|
||||
$roomId = $request->input('room_id');
|
||||
$superLevel = (int) Sysparam::getValue('superlevel', '100');
|
||||
|
||||
// 需要站长权限才能全员清屏
|
||||
if ($admin->user_level < $superLevel) {
|
||||
return response()->json(['status' => 'error', 'message' => '仅站长可执行全员清屏'], 403);
|
||||
// 改为按职务权限控制聊天室顶部“清屏”按钮。
|
||||
if (! $this->positionPermissionService->hasPermission($admin, PositionPermissionRegistry::ROOM_CLEAR_SCREEN)) {
|
||||
return response()->json(['status' => 'error', 'message' => '当前职务无权执行全员清屏'], 403);
|
||||
}
|
||||
|
||||
// 清除 Redis 中该房间的消息缓存
|
||||
@@ -427,7 +453,7 @@ class AdminCommandController extends Controller
|
||||
* 管理员触发全屏特效。
|
||||
*
|
||||
* 向房间内所有用户广播 EffectBroadcast 事件,前端收到后播放对应 Canvas 动画。
|
||||
* 仅 superlevel 等级管理员可触发。
|
||||
* 仅拥有 room.fullscreen_effect 权限的职务可触发。
|
||||
*
|
||||
* @param Request $request 请求对象,需包含 room_id, type
|
||||
* @return JsonResponse 操作结果
|
||||
@@ -442,11 +468,8 @@ class AdminCommandController extends Controller
|
||||
$admin = Auth::user();
|
||||
$roomId = $request->input('room_id');
|
||||
$type = $request->input('type');
|
||||
$superLevel = (int) Sysparam::getValue('superlevel', '100');
|
||||
|
||||
// 仅 superlevel 等级可触发特效
|
||||
if ($admin->user_level < $superLevel) {
|
||||
return response()->json(['status' => 'error', 'message' => '仅站长可触发特效'], 403);
|
||||
if (! $this->positionPermissionService->hasPermission($admin, PositionPermissionRegistry::ROOM_FULLSCREEN_EFFECT)) {
|
||||
return response()->json(['status' => 'error', 'message' => '当前职务无权触发特效'], 403);
|
||||
}
|
||||
|
||||
// 广播特效事件给房间内所有在线用户
|
||||
|
||||
@@ -26,9 +26,11 @@ use App\Models\User;
|
||||
use App\Services\AppointmentService;
|
||||
use App\Services\ChatStateService;
|
||||
use App\Services\MessageFilterService;
|
||||
use App\Services\PositionPermissionService;
|
||||
use App\Services\RoomBroadcastService;
|
||||
use App\Services\UserCurrencyService;
|
||||
use App\Services\VipService;
|
||||
use App\Support\PositionPermissionRegistry;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
@@ -58,6 +60,7 @@ class ChatController extends Controller
|
||||
private readonly UserCurrencyService $currencyService,
|
||||
private readonly AppointmentService $appointmentService,
|
||||
private readonly RoomBroadcastService $broadcast,
|
||||
private readonly PositionPermissionService $positionPermissionService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -278,7 +281,9 @@ class ChatController extends Controller
|
||||
];
|
||||
}
|
||||
|
||||
// 渲染主聊天框架视图
|
||||
// 渲染主聊天框架视图前,先计算当前用户的聊天室顶部管理权限。
|
||||
$roomPermissionMap = $this->positionPermissionService->permissionMapForUser($user);
|
||||
|
||||
return view('chat.frame', [
|
||||
'room' => $room,
|
||||
'user' => $user,
|
||||
@@ -289,6 +294,8 @@ class ChatController extends Controller
|
||||
'historyMessages' => $historyMessages,
|
||||
'pendingProposal' => $pendingProposalData,
|
||||
'pendingDivorce' => $pendingDivorceData,
|
||||
'roomPermissionMap' => $roomPermissionMap,
|
||||
'hasRoomManagementPermission' => in_array(true, $roomPermissionMap, true),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -892,7 +899,8 @@ class ChatController extends Controller
|
||||
|
||||
/**
|
||||
* 设置房间公告/祝福语(滚动显示在聊天室顶部)
|
||||
* 需要房间主人或等级达到 level_announcement 配置值
|
||||
* 需要当前在职职务拥有 room.announcement 权限,
|
||||
* id=1 站长始终允许操作。
|
||||
*
|
||||
* @param int $id 房间ID
|
||||
*/
|
||||
@@ -901,9 +909,8 @@ class ChatController extends Controller
|
||||
$user = Auth::user();
|
||||
$room = Room::findOrFail($id);
|
||||
|
||||
// 权限检查:房间主人 或 等级 >= level_announcement
|
||||
$requiredLevel = (int) Sysparam::getValue('level_announcement', '10');
|
||||
if ($user->username !== $room->master && $user->user_level < $requiredLevel) {
|
||||
// 改为统一走职务权限判断,不再给房主单独保留公告特权。
|
||||
if (! $this->positionPermissionService->hasPermission($user, PositionPermissionRegistry::ROOM_ANNOUNCEMENT)) {
|
||||
return response()->json(['status' => 'error', 'message' => '权限不足,无法修改公告'], 403);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* 文件功能:聊天室礼包(红包)控制器
|
||||
*
|
||||
* 提供两个核心接口:
|
||||
* - send() :superlevel 站长凭空发出 888 数量 10 份礼包(金币 or 经验)
|
||||
* - send() :拥有权限的职务用户凭空发出 8888 数量 10 份礼包(金币 or 经验)
|
||||
* - claim() :在线用户抢礼包(先到先得,每人一份)
|
||||
*
|
||||
* 接入 UserCurrencyService 记录所有货币变动流水。
|
||||
@@ -23,9 +23,10 @@ use App\Events\RedPacketSent;
|
||||
use App\Jobs\SaveMessageJob;
|
||||
use App\Models\RedPacketClaim;
|
||||
use App\Models\RedPacketEnvelope;
|
||||
use App\Models\Sysparam;
|
||||
use App\Services\ChatStateService;
|
||||
use App\Services\PositionPermissionService;
|
||||
use App\Services\UserCurrencyService;
|
||||
use App\Support\PositionPermissionRegistry;
|
||||
use Illuminate\Database\UniqueConstraintViolationException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -54,10 +55,11 @@ class RedPacketController extends Controller
|
||||
public function __construct(
|
||||
private readonly ChatStateService $chatState,
|
||||
private readonly UserCurrencyService $currencyService,
|
||||
private readonly PositionPermissionService $positionPermissionService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* superlevel 站长凭空发出礼包。
|
||||
* 拥有权限的职务用户凭空发出礼包。
|
||||
*
|
||||
* 不扣发包人自身货币,888 数量凭空发出分 10 份。
|
||||
* type 参数决定本次发出的是金币(gold)还是经验(exp)。
|
||||
@@ -75,10 +77,9 @@ class RedPacketController extends Controller
|
||||
$roomId = (int) $request->input('room_id');
|
||||
$type = $request->input('type'); // 'gold' 或 'exp'
|
||||
|
||||
// 权限校验:仅 superlevel 可发礼包
|
||||
$superLevel = (int) Sysparam::getValue('superlevel', '100');
|
||||
if ($user->user_level < $superLevel) {
|
||||
return response()->json(['status' => 'error', 'message' => '仅站长可发礼包红包'], 403);
|
||||
// 改为按职务权限码控制礼包发放。
|
||||
if (! $this->positionPermissionService->hasPermission($user, PositionPermissionRegistry::ROOM_RED_PACKET)) {
|
||||
return response()->json(['status' => 'error', 'message' => '当前职务无权发礼包红包'], 403);
|
||||
}
|
||||
|
||||
// 检查该用户在此房间是否有进行中的红包(防止刷包)
|
||||
|
||||
Reference in New Issue
Block a user