- 修复 LeaderboardController 查询不存在的 sign 字段导致 500 错误 - 修复 leaderboard/index 和 guestbook/index 引用不存在的 layouts.app 布局 - 将排行榜和留言板改为独立 HTML 页面结构(含 Tailwind CDN) - 修复退出登录返回 JSON 而非重定向的问题,现在会正确跳转回登录页 - 将 REDIS_CLIENT 从 phpredis 改为 predis(兼容无扩展环境) - 新增 RoomSeeder 自动创建默认公共大厅房间 - 新增 Nginx 生产环境配置示例(含 WebSocket 反向代理) - 重写 README.md 为完整的中文部署指南 - 修复 rooms/index 和 chat/frame 中 Alpine.js 语法错误 - 将 chat.js 加入 Vite 构建配置 - 新增验证码配置文件
436 lines
25 KiB
PHP
436 lines
25 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>聊天大厅 - 飘落流星</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<!-- 引入 Alpine.js 用于简单的无代码弹窗切换 -->
|
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
|
<style>
|
|
.custom-scrollbar::-webkit-scrollbar {
|
|
width: 8px;
|
|
}
|
|
|
|
.custom-scrollbar::-webkit-scrollbar-thumb {
|
|
background-color: #cbd5e1;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.custom-scrollbar::-webkit-scrollbar-track {
|
|
background-color: transparent;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body class="bg-gray-100 min-h-screen text-gray-800" x-data="{
|
|
showCreateModal: false,
|
|
showEditModal: false,
|
|
showTransferModal: false,
|
|
showProfileModal: false,
|
|
showPasswordModal: false,
|
|
currentRoom: null
|
|
}">
|
|
|
|
<!-- 顶部导航条 -->
|
|
<nav class="bg-indigo-600 px-6 py-4 shadow-md sticky top-0 z-50">
|
|
<div class="max-w-7xl mx-auto flex justify-between items-center text-white">
|
|
<div class="flex items-center space-x-4">
|
|
<span class="text-xl">🌟</span>
|
|
<h1 class="text-xl font-extrabold tracking-wider">星光大厅</h1>
|
|
</div>
|
|
|
|
<!-- 右侧操作区 -->
|
|
<div class="flex items-center space-x-3 text-sm">
|
|
|
|
<!-- 留言板入口 -->
|
|
<a href="{{ route('guestbook.index') }}"
|
|
class="text-indigo-100 hover:text-white font-bold flex items-center bg-indigo-800/40 px-3 py-1.5 rounded-full transition shadow-inner">
|
|
<span class="mr-1">✉️</span> 留言板
|
|
</a>
|
|
|
|
<!-- 风云排行榜入口 -->
|
|
<a href="{{ route('leaderboard.index') }}"
|
|
class="mr-4 text-yellow-400 hover:text-yellow-300 font-bold flex items-center bg-indigo-800/50 px-3 py-1.5 rounded-full transition shadow-inner">
|
|
<span class="mr-1">🏆</span> 风云榜
|
|
</a>
|
|
|
|
<!-- admin 后台直达 -->
|
|
@if (Auth::user()->user_level >= 15)
|
|
<a href="{{ route('admin.dashboard') }}"
|
|
class="mr-4 text-indigo-200 hover:text-white font-bold hidden sm:block">⚙️ 后台管理</a>
|
|
@endif
|
|
<!-- 点击直接在本页弹出资料卡修改 -->
|
|
<button @click="showProfileModal = true"
|
|
class="font-medium text-sm hover:text-indigo-200 transition flex items-center">
|
|
欢迎您,{{ Auth::user()->username }}
|
|
<span
|
|
class="bg-white/20 px-2 py-0.5 rounded-full text-xs ml-2 border border-white/10 shadow-sm">LV.{{ Auth::user()->user_level }}</span>
|
|
</button>
|
|
|
|
{{-- 权限按钮区 --}}
|
|
@if (Auth::user()->user_level >= 10)
|
|
<button @click="showCreateModal = true"
|
|
class="bg-emerald-500 hover:bg-emerald-400 px-4 py-2 rounded-md font-bold text-sm transition shadow-sm">
|
|
+ 新建房间
|
|
</button>
|
|
@endif
|
|
|
|
<form action="{{ route('logout') }}" method="POST" class="inline">
|
|
@csrf
|
|
<button type="submit"
|
|
class="text-sm border border-white/30 hover:bg-white/10 px-4 py-2 rounded-md transition font-medium">退出登录</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- 主展示区 -->
|
|
<main class="max-w-7xl mx-auto py-10 px-6">
|
|
|
|
<!-- 全局提示消息 -->
|
|
@if (session('success'))
|
|
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4 mb-8 rounded shadow-sm">
|
|
<p class="font-bold">操作成功</p>
|
|
<p>{{ session('success') }}</p>
|
|
</div>
|
|
@endif
|
|
@if (session('error'))
|
|
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-8 rounded shadow-sm">
|
|
<p class="font-bold">发生错误</p>
|
|
<p>{{ session('error') }}</p>
|
|
</div>
|
|
@endif
|
|
@if ($errors->any())
|
|
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-8 rounded shadow-sm">
|
|
<ul class="list-disc list-inside text-sm">
|
|
@foreach ($errors->all() as $error)
|
|
<li>{{ $error }}</li>
|
|
@endforeach
|
|
</ul>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="mb-6 flex justify-between items-end border-b pb-4">
|
|
<h2 class="text-xl font-bold text-gray-700">公开频段 (<span
|
|
class="text-indigo-600">{{ $rooms->count() }}</span>)</h2>
|
|
</div>
|
|
|
|
<!-- 房间瀑布流网格 -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
|
@forelse($rooms as $room)
|
|
<div
|
|
class="bg-white rounded-xl shadow-sm hover:shadow-lg transition-shadow border border-gray-100 overflow-hidden flex flex-col group {{ $room->is_system ? 'ring-2 ring-indigo-500/20' : '' }}">
|
|
|
|
{{-- 卡片头部 --}}
|
|
<div class="p-5 flex-1 relative">
|
|
@if ($room->is_system)
|
|
<span
|
|
class="absolute top-4 right-4 bg-indigo-100 text-indigo-700 text-xs font-bold px-2 py-1 rounded-sm">官方驻地</span>
|
|
@endif
|
|
<h3 class="text-xl font-bold text-gray-800 mb-2 truncate" title="{{ $room->name }}">
|
|
{{ $room->name }}</h3>
|
|
<p class="text-sm text-gray-500 line-clamp-2 h-10 mb-4">
|
|
{{ $room->description ?: '房主很懒,什么都没写...' }}</p>
|
|
<div class="flex items-center text-xs text-gray-400 font-medium">
|
|
<span>房主:<span
|
|
class="{{ $room->master == Auth::user()->username ? 'text-indigo-600 font-bold' : 'text-gray-600' }}">{{ $room->master }}</span></span>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- 底部操作区 --}}
|
|
<div class="bg-gray-50 p-4 border-t border-gray-100 flex items-center justify-between">
|
|
|
|
{{-- 管理按钮组(仅房主或超管可见) --}}
|
|
<div class="flex space-x-2">
|
|
@if ($room->master == Auth::user()->username || Auth::user()->user_level >= 15)
|
|
<!-- 修改 -->
|
|
<button
|
|
@click="currentRoom = {id: {{ $room->id }}, name: '{{ addslashes($room->name) }}', description: '{{ addslashes($room->description) }}'}; showEditModal = true"
|
|
class="text-xs text-blue-600 hover:text-blue-800 font-semibold px-2 py-1 rounded hover:bg-blue-50 transition">
|
|
管理
|
|
</button>
|
|
|
|
@if (!$room->is_system)
|
|
<!-- 转让 -->
|
|
<button
|
|
@click="currentRoom = {id: {{ $room->id }}, name: '{{ addslashes($room->name) }}'}; showTransferModal = true"
|
|
class="text-xs text-amber-600 hover:text-amber-800 font-semibold px-2 py-1 rounded hover:bg-amber-50 transition">
|
|
转让
|
|
</button>
|
|
<!-- 删除 -->
|
|
<form action="{{ route('rooms.destroy', $room->id) }}" method="POST"
|
|
class="inline"
|
|
onsubmit="return confirm('警告:确实要彻底解散「{{ $room->name }}」吗?此操作不可逆!');">
|
|
@csrf @method('delete')
|
|
<button type="submit"
|
|
class="text-xs text-red-600 hover:text-red-800 font-semibold px-2 py-1 rounded hover:bg-red-50 transition">解散</button>
|
|
</form>
|
|
@endif
|
|
@endif
|
|
</div>
|
|
|
|
{{-- 进入按钮 --}}
|
|
<a href="{{ route('chat.room', $room->id) }}"
|
|
class="bg-indigo-600 text-white hover:bg-indigo-700 px-4 py-2 rounded-t-xl rounded-br-xl text-sm font-bold shadow-md hover:shadow-lg transition-all transform group-hover:-translate-y-0.5">
|
|
立刻进入 →
|
|
</a>
|
|
</div>
|
|
</div>
|
|
@empty
|
|
<div class="col-span-full py-20 text-center text-gray-400">
|
|
<p class="text-xl font-bold mb-2">大厅空空如也</p>
|
|
<p>目前还没有人创建任何房间。</p>
|
|
</div>
|
|
@endforelse
|
|
</div>
|
|
</main>
|
|
|
|
<!-- 新建房间 Modal (通过 Alpine.js 开关) -->
|
|
<div x-show="showCreateModal" style="display: none;"
|
|
class="fixed inset-0 z-[100] bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
|
|
<div @click.away="showCreateModal = false"
|
|
class="bg-white rounded-2xl shadow-2xl w-full max-w-md overflow-hidden transform transition-all"
|
|
x-transition.scale.95>
|
|
<div class="bg-gray-50 border-b px-6 py-4 flex justify-between items-center">
|
|
<h3 class="font-bold text-lg text-gray-800">新建私人聊天频道</h3>
|
|
<button @click="showCreateModal = false"
|
|
class="text-gray-400 hover:text-gray-600 font-bold text-xl">×</button>
|
|
</div>
|
|
<form action="{{ route('rooms.store') }}" method="POST" class="p-6">
|
|
@csrf
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-bold text-gray-700 mb-2">频道名称 <span
|
|
class="text-red-500">*</span></label>
|
|
<input type="text" name="name" required maxlength="50" placeholder="例如:技术交流水群"
|
|
class="w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500 p-2.5 bg-gray-50 border">
|
|
</div>
|
|
<div class="mb-6">
|
|
<label class="block text-sm font-bold text-gray-700 mb-2">频道主题描述</label>
|
|
<textarea name="description" rows="3" maxlength="255" placeholder="一句话介绍这里的规矩..."
|
|
class="w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500 p-2.5 bg-gray-50 border resize-none"></textarea>
|
|
</div>
|
|
<div class="flex justify-end space-x-3">
|
|
<button type="button" @click="showCreateModal = false"
|
|
class="px-4 py-2 bg-white border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 font-medium">取消</button>
|
|
<button type="submit"
|
|
class="px-6 py-2 bg-emerald-600 text-white rounded-md font-bold hover:bg-emerald-700 shadow-sm">立即创建</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 修改管理 Modal -->
|
|
<div x-show="showEditModal" style="display: none;"
|
|
class="fixed inset-0 z-[100] bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
|
|
<div @click.away="showEditModal = false"
|
|
class="bg-white rounded-2xl shadow-2xl w-full max-w-md overflow-hidden transform transition-all"
|
|
x-transition.scale.95>
|
|
<div class="bg-blue-50 border-b border-blue-100 px-6 py-4 flex justify-between items-center">
|
|
<h3 class="font-bold text-lg text-blue-900" x-text="'管理频道: ' + currentRoom?.name"></h3>
|
|
<button @click="showEditModal = false"
|
|
class="text-blue-400 hover:text-blue-600 font-bold text-xl">×</button>
|
|
</div>
|
|
<!-- 注意这里通过 Alpine 动态拼接 action 路径 -->
|
|
<form :action="'{{ url('rooms') }}/' + currentRoom?.id" method="POST" class="p-6">
|
|
@csrf @method('PUT')
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-bold text-gray-700 mb-2">频道新名称 <span
|
|
class="text-red-500">*</span></label>
|
|
<input type="text" name="name" :value="currentRoom?.name" required maxlength="50"
|
|
class="w-full border-gray-300 rounded-md shadow-sm focus:border-blue-500 focus:ring-blue-500 p-2.5 bg-gray-50 border">
|
|
</div>
|
|
<div class="mb-6">
|
|
<label class="block text-sm font-bold text-gray-700 mb-2">更新主题描述</label>
|
|
<textarea name="description" x-text="currentRoom?.description" rows="3" maxlength="255"
|
|
class="w-full border-gray-300 rounded-md shadow-sm focus:border-blue-500 focus:ring-blue-500 p-2.5 bg-gray-50 border resize-none"></textarea>
|
|
</div>
|
|
<div class="flex justify-end space-x-3">
|
|
<button type="button" @click="showEditModal = false"
|
|
class="px-4 py-2 bg-white border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 font-medium">关闭</button>
|
|
<button type="submit"
|
|
class="px-6 py-2 bg-blue-600 text-white rounded-md font-bold hover:bg-blue-700 shadow-sm">保存并广播</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 转让房主 Modal -->
|
|
<div x-show="showTransferModal" style="display: none;"
|
|
class="fixed inset-0 z-[100] bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
|
|
<div @click.away="showTransferModal = false"
|
|
class="bg-white rounded-2xl shadow-2xl w-full max-w-sm overflow-hidden transform transition-all"
|
|
x-transition.scale.95>
|
|
<div class="bg-amber-50 border-b border-amber-100 px-6 py-4 flex justify-between items-center">
|
|
<h3 class="font-bold text-lg text-amber-900" x-text="'转让授权: ' + currentRoom?.name"></h3>
|
|
<button @click="showTransferModal = false"
|
|
class="text-amber-400 hover:text-amber-600 font-bold text-xl">×</button>
|
|
</div>
|
|
<form :action="'{{ url('rooms') }}/' + currentRoom?.id + '/transfer'" method="POST" class="p-6">
|
|
@csrf
|
|
<div class="bg-amber-100 text-amber-800 text-xs p-3 rounded mb-4">
|
|
转让后您将立即失去对该房间的管理权限,请谨慎操作。
|
|
</div>
|
|
<div class="mb-6">
|
|
<label class="block text-sm font-bold text-gray-700 mb-2">接收人昵称 <span
|
|
class="text-red-500">*</span></label>
|
|
<input type="text" name="target_username" required placeholder="请输入对方准确用户名"
|
|
class="w-full border-gray-300 rounded-md shadow-sm focus:border-amber-500 focus:ring-amber-500 p-2.5 bg-gray-50 border">
|
|
</div>
|
|
<div class="flex justify-end space-x-3">
|
|
<button type="button" @click="showTransferModal = false"
|
|
class="px-4 py-2 bg-white border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 font-medium">取消</button>
|
|
<button type="submit"
|
|
class="px-6 py-2 bg-amber-600 text-white rounded-md font-bold hover:bg-amber-700 shadow-sm">确认转让</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 个人资料设置 Modal -->
|
|
<div x-show="showProfileModal" style="display: none;"
|
|
class="fixed inset-0 z-[100] bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
|
|
<div @click.away="showProfileModal = false"
|
|
class="bg-white rounded-2xl shadow-2xl w-full max-w-md overflow-hidden transform transition-all"
|
|
x-transition.scale.95>
|
|
<div
|
|
class="bg-gradient-to-r from-indigo-500 to-purple-600 px-6 py-4 flex justify-between items-center text-white">
|
|
<h3 class="font-bold text-lg">个人资料设置</h3>
|
|
<button @click="showProfileModal = false"
|
|
class="text-white/80 hover:text-white font-bold text-xl">×</button>
|
|
</div>
|
|
|
|
<div class="p-6" x-data="{
|
|
profileData: {
|
|
sex: '{{ Auth::user()->sex }}',
|
|
sign: '{{ Auth::user()->sign }}',
|
|
headface: '{{ Auth::user()->headface ?? '01.gif' }}'
|
|
},
|
|
isSaving: false,
|
|
|
|
async saveProfile() {
|
|
this.isSaving = true;
|
|
try {
|
|
const res = await fetch('{{ route('user.update_profile') }}', {
|
|
method: 'PUT',
|
|
headers: {
|
|
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'), 'Content-Type'
|
|
: 'application/json' , 'Accept' : 'application/json' }, body: JSON.stringify(this.profileData) }); const
|
|
data=await res.json(); if (res.ok && data.status === 'success') { alert(data.message);
|
|
window.location.reload(); } else { alert('保存失败: ' + (data.message || ' 输入有误')); } } catch (e) {
|
|
alert('网络异常'); } finally { this.isSaving=false; } } }">
|
|
<form @submit.prevent="saveProfile">
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-bold text-gray-700 mb-2">性别</label>
|
|
<select x-model="profileData.sex"
|
|
class="w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500 p-2.5 bg-gray-50 border">
|
|
<option value="男">男生</option>
|
|
<option value="女">女生</option>
|
|
<option value="保密">保密</option>
|
|
</select>
|
|
</div>
|
|
<!-- 头像选择 (暂时写死输入框,后续可优化为网格选择) -->
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-bold text-gray-700 mb-2">头像选择 (01.gif - 50.gif)</label>
|
|
<div class="flex items-center space-x-3">
|
|
<div class="w-12 h-12 rounded bg-gray-200 shrink-0 overflow-hidden border">
|
|
<img :src="'/images/headface/' + profileData.headface"
|
|
@@error="$el.style.display='none'"
|
|
class="w-full h-full object-cover">
|
|
</div>
|
|
<input type="text" x-model="profileData.headface" required
|
|
class="flex-1 border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500 p-2.5 bg-gray-50 border">
|
|
</div>
|
|
</div>
|
|
<div class="mb-6">
|
|
<label class="block text-sm font-bold text-gray-700 mb-2">个性签名</label>
|
|
<textarea x-model="profileData.sign" rows="2" maxlength="255" placeholder="写点什么吧..."
|
|
class="w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500 p-2.5 bg-gray-50 border resize-none"></textarea>
|
|
</div>
|
|
<div class="flex justify-between items-center border-t pt-4">
|
|
<button type="button" @click="showProfileModal = false; showPasswordModal = true"
|
|
class="text-sm text-indigo-600 hover:text-indigo-800 font-bold hover:underline">修改安全密码</button>
|
|
<div class="space-x-2">
|
|
<button type="button" @click="showProfileModal = false"
|
|
class="px-4 py-2 bg-white border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 font-medium cursor-pointer">取消</button>
|
|
<button type="submit" :disabled="isSaving"
|
|
class="px-6 py-2 bg-indigo-600 text-white rounded-md font-bold hover:bg-indigo-700 shadow-sm disabled:opacity-50 cursor-pointer">保存资料</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 修改密码 Modal -->
|
|
<div x-show="showPasswordModal" style="display: none;"
|
|
class="fixed inset-0 z-[110] bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
|
|
<div @click.away="showPasswordModal = false"
|
|
class="bg-white rounded-2xl shadow-2xl w-full max-w-sm overflow-hidden transform transition-all"
|
|
x-transition.scale.95>
|
|
<div class="bg-gray-800 px-6 py-4 flex justify-between items-center text-white">
|
|
<h3 class="font-bold text-lg">修改安全密码</h3>
|
|
<button @click="showPasswordModal = false"
|
|
class="text-gray-400 hover:text-white font-bold text-xl">×</button>
|
|
</div>
|
|
|
|
<div class="p-6" x-data="{
|
|
pwdData: {
|
|
old_password: '',
|
|
new_password: '',
|
|
new_password_confirmation: ''
|
|
},
|
|
isSaving: false,
|
|
|
|
async savePassword() {
|
|
if (this.pwdData.new_password !== this.pwdData.new_password_confirmation) {
|
|
alert('两次输入的新密码不一致!');
|
|
return;
|
|
}
|
|
if (this.pwdData.new_password.length < 6) {
|
|
alert('新密码最少 6 位!');
|
|
return;
|
|
}
|
|
this.isSaving = true;
|
|
try {
|
|
const res = await fetch('{{ route('user.update_password') }}', {
|
|
method: 'PUT',
|
|
headers: {
|
|
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'), 'Content-Type'
|
|
: 'application/json' , 'Accept' : 'application/json' }, body: JSON.stringify(this.pwdData) }); const
|
|
data=await res.json(); if (res.ok && data.status === 'success') { alert(data.message);
|
|
window.location.href = '{{ route('home') }}'; // 改密成功重新登录 } else {
|
|
alert('密码修改失败: ' + (data.message || ' 请输入正确的旧密码')); } } catch (e) { alert('网络异常'); } finally {
|
|
this.isSaving=false; } } }">
|
|
<form @submit.prevent="savePassword">
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-bold text-gray-700 mb-2">当前旧密码</label>
|
|
<input type="password" x-model="pwdData.old_password" required
|
|
class="w-full border-gray-300 rounded-md shadow-sm focus:border-gray-500 focus:ring-gray-500 p-2.5 bg-gray-50 border">
|
|
</div>
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-bold text-gray-700 mb-2">新密码</label>
|
|
<input type="password" x-model="pwdData.new_password" required placeholder="至少 6 位字母或数字"
|
|
class="w-full border-gray-300 rounded-md shadow-sm focus:border-gray-500 focus:ring-gray-500 p-2.5 bg-gray-50 border">
|
|
</div>
|
|
<div class="mb-6">
|
|
<label class="block text-sm font-bold text-gray-700 mb-2">确认新密码</label>
|
|
<input type="password" x-model="pwdData.new_password_confirmation" required
|
|
class="w-full border-gray-300 rounded-md shadow-sm focus:border-gray-500 focus:ring-gray-500 p-2.5 bg-gray-50 border">
|
|
</div>
|
|
<div class="flex justify-end space-x-3 border-t pt-4">
|
|
<button type="button" @click="showPasswordModal = false"
|
|
class="px-4 py-2 bg-white border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 font-medium cursor-pointer">取消</button>
|
|
<button type="submit" :disabled="isSaving"
|
|
class="px-6 py-2 bg-gray-800 text-white rounded-md font-bold hover:bg-gray-900 shadow-sm disabled:opacity-50 cursor-pointer">确定修改</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</body>
|
|
|
|
</html>
|