148 lines
5.2 KiB
PHP
148 lines
5.2 KiB
PHP
|
|
<?php
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 文件功能:聊天室内快速任命/撤销控制器
|
|||
|
|
* 供有职务的管理员在聊天室用户名片弹窗中快速任命或撤销目标用户的职务。
|
|||
|
|
* 权限校验委托给 AppointmentService,本控制器只做请求解析和返回 JSON。
|
|||
|
|
*
|
|||
|
|
* @author ChatRoom Laravel
|
|||
|
|
*
|
|||
|
|
* @version 1.0.0
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
namespace App\Http\Controllers;
|
|||
|
|
|
|||
|
|
use App\Events\AppointmentAnnounced;
|
|||
|
|
use App\Models\Position;
|
|||
|
|
use App\Models\User;
|
|||
|
|
use App\Services\AppointmentService;
|
|||
|
|
use App\Services\ChatStateService;
|
|||
|
|
use Illuminate\Http\JsonResponse;
|
|||
|
|
use Illuminate\Http\Request;
|
|||
|
|
use Illuminate\Support\Facades\Auth;
|
|||
|
|
|
|||
|
|
class ChatAppointmentController extends Controller
|
|||
|
|
{
|
|||
|
|
/**
|
|||
|
|
* 注入任命服务
|
|||
|
|
*/
|
|||
|
|
public function __construct(
|
|||
|
|
private readonly AppointmentService $appointmentService,
|
|||
|
|
private readonly ChatStateService $chatState,
|
|||
|
|
) {}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取可用职务列表(供名片弹窗下拉选择)
|
|||
|
|
* 返回操作人有权限任命的职务
|
|||
|
|
*/
|
|||
|
|
public function positions(): JsonResponse
|
|||
|
|
{
|
|||
|
|
$operator = Auth::user();
|
|||
|
|
$superLevel = (int) \App\Models\Sysparam::getValue('superlevel', '100');
|
|||
|
|
$operatorPosition = $operator->activePosition?->position;
|
|||
|
|
|
|||
|
|
$query = Position::query()
|
|||
|
|
->with('department')
|
|||
|
|
->orderByDesc('rank');
|
|||
|
|
|
|||
|
|
// 仅有具体职务(非 superlevel 直通)的操作人才限制 rank 范围
|
|||
|
|
if ($operatorPosition && $operator->user_level < $superLevel) {
|
|||
|
|
$query->where('rank', '<', $operatorPosition->rank);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$positions = $query->get()->map(fn ($p) => [
|
|||
|
|
'id' => $p->id,
|
|||
|
|
'name' => $p->name,
|
|||
|
|
'icon' => $p->icon,
|
|||
|
|
'rank' => $p->rank,
|
|||
|
|
'department' => $p->department?->name,
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
return response()->json(['status' => 'success', 'positions' => $positions]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 快速任命:将目标用户任命为指定职务
|
|||
|
|
* 成功后向操作人所在聊天室广播任命公告
|
|||
|
|
*/
|
|||
|
|
public function appoint(Request $request): JsonResponse
|
|||
|
|
{
|
|||
|
|
$request->validate([
|
|||
|
|
'username' => 'required|string|exists:users,username',
|
|||
|
|
'position_id' => 'required|exists:positions,id',
|
|||
|
|
'remark' => 'nullable|string|max:100',
|
|||
|
|
'room_id' => 'nullable|integer|exists:rooms,id',
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$operator = Auth::user();
|
|||
|
|
$target = User::where('username', $request->username)->firstOrFail();
|
|||
|
|
$position = Position::with('department')->findOrFail($request->position_id);
|
|||
|
|
|
|||
|
|
$result = $this->appointmentService->appoint($operator, $target, $position, $request->remark);
|
|||
|
|
|
|||
|
|
// 任命成功后广播礼花通知:优先用前端传来的 room_id,否则从 Redis 查操作人所在房间
|
|||
|
|
if ($result['ok']) {
|
|||
|
|
$roomId = $request->integer('room_id') ?: ($this->chatState->getUserRooms($operator->username)[0] ?? null);
|
|||
|
|
if ($roomId) {
|
|||
|
|
broadcast(new AppointmentAnnounced(
|
|||
|
|
roomId: (int) $roomId,
|
|||
|
|
targetUsername: $target->username,
|
|||
|
|
positionIcon: $position->icon ?? '🎖️',
|
|||
|
|
positionName: $position->name,
|
|||
|
|
departmentName: $position->department?->name ?? '',
|
|||
|
|
operatorName: $operator->username,
|
|||
|
|
));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return response()->json([
|
|||
|
|
'status' => $result['ok'] ? 'success' : 'error',
|
|||
|
|
'message' => $result['message'],
|
|||
|
|
], $result['ok'] ? 200 : 422);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 快速撤销:撤销目标用户当前的职务
|
|||
|
|
*/
|
|||
|
|
public function revoke(Request $request): JsonResponse
|
|||
|
|
{
|
|||
|
|
$request->validate([
|
|||
|
|
'username' => 'required|string|exists:users,username',
|
|||
|
|
'remark' => 'nullable|string|max:100',
|
|||
|
|
'room_id' => 'nullable|integer|exists:rooms,id',
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$operator = Auth::user();
|
|||
|
|
$target = User::where('username', $request->username)->firstOrFail();
|
|||
|
|
|
|||
|
|
// 撤销前先取目标当前职务信息(撤销后就查不到了)
|
|||
|
|
$activeUp = $target->activePosition?->load('position.department');
|
|||
|
|
$posIcon = $activeUp?->position?->icon ?? '🎖️';
|
|||
|
|
$posName = $activeUp?->position?->name ?? '';
|
|||
|
|
$deptName = $activeUp?->position?->department?->name ?? '';
|
|||
|
|
|
|||
|
|
$result = $this->appointmentService->revoke($operator, $target, $request->remark);
|
|||
|
|
|
|||
|
|
// 撤销成功后广播通知到聊天室
|
|||
|
|
if ($result['ok'] && $posName) {
|
|||
|
|
$roomId = $request->integer('room_id') ?: ($this->chatState->getUserRooms($operator->username)[0] ?? null);
|
|||
|
|
if ($roomId) {
|
|||
|
|
broadcast(new AppointmentAnnounced(
|
|||
|
|
roomId: (int) $roomId,
|
|||
|
|
targetUsername: $target->username,
|
|||
|
|
positionIcon: $posIcon,
|
|||
|
|
positionName: $posName,
|
|||
|
|
departmentName: $deptName,
|
|||
|
|
operatorName: $operator->username,
|
|||
|
|
type: 'revoke',
|
|||
|
|
));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return response()->json([
|
|||
|
|
'status' => $result['ok'] ? 'success' : 'error',
|
|||
|
|
'message' => $result['message'],
|
|||
|
|
], $result['ok'] ? 200 : 422);
|
|||
|
|
}
|
|||
|
|
}
|