Files
chatroom/resources/views/admin/users/index.blade.php
T

339 lines
21 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.
@extends('admin.layouts.app')
@section('title', '用户检索与管理')
@section('content')
@php
$filterLabelClass = 'block mb-1 text-xs font-semibold uppercase tracking-wider text-gray-500';
$filterInputClass = 'px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:ring-indigo-500 focus:border-indigo-500 text-sm';
$tableHeadClass = 'p-4 text-xs font-semibold uppercase tracking-wider text-gray-500';
$primaryTextClass = 'text-sm font-semibold text-gray-800';
$secondaryTextClass = 'text-xs text-gray-400';
$numericTextClass = 'text-sm font-mono';
$statusBadgeClass = 'inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-semibold border';
$actionButtonClass = 'rounded-lg px-3 py-1.5 text-xs font-semibold transition cursor-pointer';
$modalLabelClass = 'mb-1 block text-xs font-semibold uppercase tracking-wider text-gray-500';
$modalInputClass = 'w-full rounded-md border border-gray-300 p-2 text-sm text-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500';
@endphp
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden mb-6" x-data="userEditor()">
<div class="p-6 border-b border-gray-100 bg-gray-50">
<form action="{{ route('admin.users.index') }}" method="GET" class="flex flex-wrap items-end gap-3">
<div>
<label class="{{ $filterLabelClass }}">用户名</label>
<input type="text" name="username" value="{{ request('username') }}" placeholder="搜索用户名..."
class="w-64 {{ $filterInputClass }}">
</div>
<button type="submit"
class="bg-indigo-600 text-white px-4 py-2 rounded-lg font-semibold shadow-sm transition hover:bg-indigo-700">搜索</button>
<a href="{{ route('admin.users.index') }}"
class="px-4 py-2 bg-white border border-gray-300 rounded-lg text-sm font-semibold text-gray-700 hover:bg-gray-50 transition">重置</a>
</form>
</div>
<!-- 用户表格 -->
<div class="overflow-x-auto">
@php
/**
* 生成排序链接:点击同一列切换方向,点击新列默认倒序
*/
$sortLink = function (string $col) use ($sortBy, $sortDir): string {
$newDir = $sortBy === $col && $sortDir === 'desc' ? 'asc' : 'desc';
$qs = http_build_query(
array_merge(request()->except(['sort_by', 'sort_dir', 'page']), [
'sort_by' => $col,
'sort_dir' => $newDir,
]),
);
return url('/admin/users?' . $qs);
};
$arrow = fn(string $col): string => $sortBy === $col ? ($sortDir === 'desc' ? ' ↓' : ' ↑') : '';
@endphp
<table class="w-full text-left border-collapse whitespace-nowrap">
<thead>
<tr class="bg-gray-50 border-b border-gray-100">
<th class="{{ $tableHeadClass }}">
<a href="{{ $sortLink('id') }}" class="flex items-center gap-1 hover:text-indigo-600">
ID<span class="text-indigo-500">{{ $arrow('id') }}</span>
</a>
</th>
<th class="{{ $tableHeadClass }}">注册名</th>
<th class="{{ $tableHeadClass }}">性别</th>
<th class="{{ $tableHeadClass }}">
<a href="{{ $sortLink('user_level') }}" class="flex items-center gap-1 hover:text-indigo-600">
等级<span class="text-indigo-500">{{ $arrow('user_level') }}</span>
</a>
</th>
<th class="{{ $tableHeadClass }}">职务</th>
<th class="{{ $tableHeadClass }}">
<a href="{{ $sortLink('exp_num') }}" class="flex items-center gap-1 hover:text-indigo-600">
经验<span class="text-indigo-500">{{ $arrow('exp_num') }}</span>
</a>
</th>
<th class="{{ $tableHeadClass }}">
<a href="{{ $sortLink('jjb') }}" class="flex items-center gap-1 hover:text-yellow-600">
金币<span class="text-yellow-500">{{ $arrow('jjb') }}</span>
</a>
</th>
<th class="{{ $tableHeadClass }}">
<a href="{{ $sortLink('meili') }}" class="flex items-center gap-1 hover:text-pink-600">
魅力<span class="text-pink-500">{{ $arrow('meili') }}</span>
</a>
</th>
<th class="{{ $tableHeadClass }}">注册时间</th>
<th class="{{ $tableHeadClass }}">
<a href="{{ $sortLink('wxid') }}" class="flex items-center gap-1 hover:text-green-600">
微信绑定<span class="text-green-500">{{ $arrow('wxid') }}</span>
</a>
</th>
<th class="{{ $tableHeadClass }}">
<a href="{{ $sortLink('online') }}" class="flex items-center gap-1 hover:text-green-600">
在线<span class="text-green-500">{{ $arrow('online') }}</span>
</a>
</th>
<th class="{{ $tableHeadClass }} text-right">管理操作</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
@foreach ($users as $user)
<tr class="hover:bg-gray-50 transition">
<td class="p-4 text-xs font-mono text-gray-500">{{ $user->id }}</td>
<td class="p-4">
<div class="flex items-center space-x-3">
<img src="{{ $user->headface_url ?? '/images/headface/1.gif' }}"
class="w-8 h-8 rounded border object-cover">
<span class="{{ $primaryTextClass }}">{{ $user->username }}</span>
@if ($user->isVip())
<span title="{{ $user->vipName() }}"
style="color: {{ $user->vipLevel?->color ?? '#f59e0b' }}">{{ $user->vipIcon() }}</span>
@endif
</div>
</td>
<td class="p-4 text-sm">{{ [0 => '保密', 1 => '男', 2 => '女'][$user->sex] ?? '保密' }}</td>
<td class="p-4">
<span
class="px-2 py-0.5 rounded-full text-xs {{ $user->user_level >= 100 ? 'bg-red-100 text-red-700 font-bold' : 'bg-gray-100 text-gray-600' }}">
LV.{{ $user->user_level }}
</span>
</td>
<td class="p-4">
@if ($user->activePosition)
@php $pos = $user->activePosition->position; @endphp
<div class="{{ $secondaryTextClass }}">{{ $pos->department->name }}</div>
<div class="font-semibold text-sm" style="color: {{ $pos->department->color }}">
{{ $pos->icon }} {{ $pos->name }}
</div>
@else
<span class="text-gray-300 text-xs"></span>
@endif
</td>
<td class="p-4 {{ $numericTextClass }} text-gray-600">
{{ number_format($user->exp_num ?? 0) }}
</td>
<td class="p-4 {{ $numericTextClass }} text-yellow-700">
{{ number_format($user->jjb ?? 0) }}
</td>
<td class="p-4 {{ $numericTextClass }} text-pink-600">
{{ number_format($user->meili ?? 0) }}
</td>
<td class="p-4 {{ $numericTextClass }} text-gray-500">{{ $user->created_at->format('y-m-d') }}
</td>
<td class="p-4">
@if(!empty($user->wxid))
<span class="{{ $statusBadgeClass }} bg-green-50 text-green-700 border-green-200">
已绑定
</span>
@else
<span class="{{ $statusBadgeClass }} bg-gray-50 text-gray-400 border-gray-200">
未绑定
</span>
@endif
</td>
<td class="p-4">
@php $isOnline = $onlineUsernames->contains($user->username); @endphp
<span
class="{{ $statusBadgeClass }}
{{ $isOnline ? 'bg-green-100 text-green-700 border-green-200' : 'bg-gray-100 text-gray-400 border-gray-200' }}">
<span
class="w-1.5 h-1.5 rounded-full {{ $isOnline ? 'bg-green-500' : 'bg-gray-300' }}"></span>
{{ $isOnline ? '在线' : '离线' }}
</span>
</td>
<td class="p-4 text-right space-x-2 relative">
@if (auth()->id() === 1)
<button
@click="editingUser = {
id: {{ $user->id }},
username: '{{ addslashes($user->username) }}',
exp_num: {{ $user->exp_num ?? 0 }},
jjb: {{ $user->jjb ?? 0 }},
meili: {{ $user->meili ?? 0 }},
sex: '{{ $user->sex }}',
qianming: '{{ addslashes($user->qianming ?? '') }}',
position_id: '{{ $user->activePosition?->position_id ?? '' }}',
visit_num: {{ $user->visit_num ?? 0 }},
vip_level_id: '{{ $user->vip_level_id ?? '' }}',
hy_time: '{{ $user->hy_time ? $user->hy_time->format('Y-m-d') : '' }}',
requestUrl: '{{ route('admin.users.update', $user->id) }}'
}; showEditModal = true"
class="text-xs bg-indigo-50 text-indigo-600 font-bold px-3 py-1.5 rounded hover:bg-indigo-600 hover:text-white transition cursor-pointer">
修改
</button>
<form action="{{ route('admin.users.destroy', $user->id) }}" method="POST"
class="inline"
data-admin-confirm="危险:确定彻底物理清除用户 [{{ $user->username }}] 吗?数据不可恢复!">
@csrf @method('DELETE')
<button type="submit"
class="text-xs bg-red-50 text-red-600 font-bold px-3 py-1.5 rounded hover:bg-red-600 hover:text-white transition cursor-pointer">
强杀
</button>
</form>
@else
<span class="text-xs text-gray-300 italic"></span>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<!-- 分页链接 -->
@if ($users->hasPages())
<div class="p-4 border-t border-gray-100 text-sm text-gray-600">
{{ $users->links() }}
</div>
@endif
<!-- 弹出的修改框 -->
<div x-show="showEditModal" style="display: none;"
class="fixed inset-0 z-50 bg-black/60 flex items-center justify-center p-4">
<div @click.away="showEditModal = false"
class="bg-white rounded-xl shadow-2xl w-full max-w-lg transform transition-all" x-transition>
<div
class="bg-indigo-900 border-b border-indigo-800 px-6 py-4 flex justify-between items-center rounded-t-xl text-white">
<h3 class="text-sm font-semibold uppercase tracking-wider">编辑用户:<span x-text="editingUser.username" class="text-indigo-300"></span>
</h3>
<button @click="showEditModal = false" class="text-gray-400 hover:text-white">&times;</button>
</div>
<div class="p-6">
{{-- Toast 通知(弹窗内部) --}}
<div x-show="editToast" x-transition style="display:none;"
:class="editToastOk ? 'bg-green-50 border-green-400 text-green-800' :
'bg-red-50 border-red-400 text-red-800'"
class="mb-4 rounded border-l-4 px-4 py-2 text-sm font-semibold" x-text="editToastMsg">
</div>
<form @submit.prevent="submitEditUser($el)" method="POST">
@csrf @method('PUT')
<div class="grid grid-cols-2 gap-4">
{{-- 经验 --}}
<div>
<label class="{{ $modalLabelClass }}">经验值</label>
<input type="number" name="exp_num" x-model="editingUser.exp_num" required
min="0"
class="{{ $modalInputClass }}">
</div>
{{-- 金币 --}}
<div>
<label class="{{ $modalLabelClass }}">金币 (jjb)</label>
<input type="number" name="jjb" x-model="editingUser.jjb" required min="0"
class="{{ $modalInputClass }}">
</div>
{{-- 魅力 --}}
<div>
<label class="{{ $modalLabelClass }}">魅力值</label>
<input type="number" name="meili" x-model="editingUser.meili" required min="0"
class="{{ $modalInputClass }}">
</div>
{{-- 性别 --}}
<div>
<label class="{{ $modalLabelClass }}">性别</label>
<select name="sex" x-model="editingUser.sex"
class="{{ $modalInputClass }}">
<option value="1"></option>
<option value="2"></option>
<option value="0">保密</option>
</select>
</div>
{{-- 访问次数 --}}
<div>
<label class="{{ $modalLabelClass }}">访问次数</label>
<input type="text" disabled :value="editingUser.visit_num"
class="w-full bg-gray-100 border-gray-200 rounded-md p-2 border text-sm text-gray-500">
</div>
</div>
{{-- 签名 --}}
<div class="mt-4">
<label class="{{ $modalLabelClass }}">个性签名</label>
<input type="text" name="qianming" x-model="editingUser.qianming" maxlength="255"
placeholder="暂无签名"
class="{{ $modalInputClass }}">
</div>
{{-- 任命职务 --}}
<div class="mt-4">
<label class="{{ $modalLabelClass }}">职务</label>
<select name="position_id" x-model="editingUser.position_id"
class="{{ $modalInputClass }}">
<option value="">无职务</option>
@foreach ($departments as $department)
<optgroup label="{{ $department->name }}">
@foreach ($department->positions as $position)
<option value="{{ $position->id }}">{{ $position->icon }} {{ $position->name }}</option>
@endforeach
</optgroup>
@endforeach
</select>
</div>
{{-- VIP 会员设置 --}}
<div class="mt-4 grid grid-cols-2 gap-4">
<div>
<label class="{{ $modalLabelClass }}">VIP 会员等级</label>
<select name="vip_level_id" x-model="editingUser.vip_level_id"
class="{{ $modalInputClass }}">
<option value="">无(普通用户)</option>
@foreach ($vipLevels as $vl)
<option value="{{ $vl->id }}">{{ $vl->icon }}
{{ $vl->name }}(×{{ $vl->exp_multiplier }}经验
×{{ $vl->jjb_multiplier }}金币)</option>
@endforeach
</select>
</div>
<div>
<label class="{{ $modalLabelClass }}">会员到期时间
<span class="normal-case font-normal tracking-normal text-gray-400">(留空=永久)</span></label>
<input type="date" name="hy_time" x-model="editingUser.hy_time"
class="{{ $modalInputClass }}">
</div>
</div>
{{-- 密码 --}}
<div class="mt-4">
<label
class="mb-1 block border-l-4 border-red-500 bg-red-50 p-2 pl-2 text-xs font-semibold uppercase tracking-wider text-red-600">强制重置密码
<span class="normal-case font-normal tracking-normal text-gray-500">(留空不修改)</span></label>
<input type="text" name="password" placeholder="输入新密码"
class="w-full border-red-300 rounded-md shadow-sm focus:border-red-500 focus:ring-red-500 p-2 border text-sm placeholder-red-300">
</div>
<div class="flex justify-end space-x-3 pt-4 mt-4 border-t border-gray-100">
<button type="button" @click="showEditModal = false"
class="px-4 py-2 border rounded font-medium text-gray-600 hover:bg-gray-50">取消</button>
<button type="submit" :disabled="editSaving"
class="px-4 py-2 bg-indigo-600 text-white rounded font-bold hover:bg-indigo-700 shadow-sm disabled:opacity-60"
x-text="editSaving ? '保存中...' : '保存修改'"></button>
</div>
</form>
</div>
</div>
</div>
</div>
@endsection