Fix: 后台用户编辑改为AJAX提交,消除302重定向,弹窗内显示成功/失败通知
This commit is contained in:
@@ -8,7 +8,7 @@
|
|||||||
// 管理员级别 = 最高等级 + 1,后台编辑最高可设到管理员级别
|
// 管理员级别 = 最高等级 + 1,后台编辑最高可设到管理员级别
|
||||||
$adminLevel = (int) \App\Models\Sysparam::getValue('maxlevel', '15') + 1;
|
$adminLevel = (int) \App\Models\Sysparam::getValue('maxlevel', '15') + 1;
|
||||||
@endphp
|
@endphp
|
||||||
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden mb-6" x-data="{ showEditModal: false, editingUser: {}, adminLevel: {{ $adminLevel }} }">
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden mb-6" x-data="{ showEditModal: false, editingUser: {}, adminLevel: {{ $adminLevel }}, editToast: false, editToastOk: true, editToastMsg: '', editSaving: false }">
|
||||||
<div class="p-6 border-b border-gray-100 bg-gray-50 flex items-center justify-between">
|
<div class="p-6 border-b border-gray-100 bg-gray-50 flex items-center justify-between">
|
||||||
<form action="{{ route('admin.users.index') }}" method="GET" class="flex gap-2">
|
<form action="{{ route('admin.users.index') }}" method="GET" class="flex gap-2">
|
||||||
<input type="text" name="username" value="{{ request('username') }}" placeholder="搜索用户名..."
|
<input type="text" name="username" value="{{ request('username') }}" placeholder="搜索用户名..."
|
||||||
@@ -117,7 +117,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
<form :action="editingUser.requestUrl" method="POST">
|
{{-- 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 px-4 py-2 border-l-4 rounded text-sm font-bold" x-text="editToastMsg">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form @submit.prevent="submitEditUser($el)" method="POST">
|
||||||
@csrf @method('PUT')
|
@csrf @method('PUT')
|
||||||
|
|
||||||
<div class="grid grid-cols-2 gap-4">
|
<div class="grid grid-cols-2 gap-4">
|
||||||
@@ -133,8 +140,11 @@
|
|||||||
min="0" :max="adminLevel"
|
min="0" :max="adminLevel"
|
||||||
:readonly="{{ Auth::id() }} !== 1 && editingUser.id !== {{ Auth::id() }}"
|
:readonly="{{ Auth::id() }} !== 1 && editingUser.id !== {{ Auth::id() }}"
|
||||||
class="w-full border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 p-2 border text-sm"
|
class="w-full border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 p-2 border text-sm"
|
||||||
:class="{ 'bg-gray-100 cursor-not-allowed': {{ Auth::id() }} !== 1 && editingUser.id !==
|
:class="{
|
||||||
{{ Auth::id() }} }"
|
'bg-gray-100 cursor-not-allowed': {{ Auth::id() }} !== 1 && editingUser
|
||||||
|
.id !==
|
||||||
|
{{ Auth::id() }}
|
||||||
|
}"
|
||||||
:title="{{ Auth::id() }} !== 1 && editingUser.id !== {{ Auth::id() }} ?
|
:title="{{ Auth::id() }} !== 1 && editingUser.id !== {{ Auth::id() }} ?
|
||||||
'仅系统创始人可修改他人等级' : ''">
|
'仅系统创始人可修改他人等级' : ''">
|
||||||
</div>
|
</div>
|
||||||
@@ -216,8 +226,9 @@
|
|||||||
<div class="flex justify-end space-x-3 pt-4 mt-4 border-t border-gray-100">
|
<div class="flex justify-end space-x-3 pt-4 mt-4 border-t border-gray-100">
|
||||||
<button type="button" @click="showEditModal = false"
|
<button type="button" @click="showEditModal = false"
|
||||||
class="px-4 py-2 border rounded font-medium text-gray-600 hover:bg-gray-50">取消</button>
|
class="px-4 py-2 border rounded font-medium text-gray-600 hover:bg-gray-50">取消</button>
|
||||||
<button type="submit"
|
<button type="submit" :disabled="editSaving"
|
||||||
class="px-4 py-2 bg-indigo-600 text-white rounded font-bold hover:bg-indigo-700 shadow-sm">保存修改</button>
|
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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -225,4 +236,51 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 用户编辑弹窗 AJAX 提交
|
||||||
|
* 避免传统表单导致 302 重定向,改为 fetch 就地显示结果
|
||||||
|
*/
|
||||||
|
async function submitEditUser(form) {
|
||||||
|
// 由 x-data 上层访问 Alpine 状态
|
||||||
|
const el = document.querySelector('[x-data]');
|
||||||
|
const data = Alpine.$data(el);
|
||||||
|
|
||||||
|
data.editSaving = true;
|
||||||
|
data.editToast = false;
|
||||||
|
|
||||||
|
const formEl = form.querySelector('form') ?? form;
|
||||||
|
const formData = new FormData(formEl);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(data.editingUser.requestUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
||||||
|
},
|
||||||
|
body: formData,
|
||||||
|
});
|
||||||
|
const json = await res.json();
|
||||||
|
|
||||||
|
data.editToastOk = json.status === 'success';
|
||||||
|
data.editToastMsg = json.message || (json.status === 'success' ? '保存成功!' : '保存失败');
|
||||||
|
data.editToast = true;
|
||||||
|
|
||||||
|
// 成功后 1.5 秒关闭弹窗
|
||||||
|
if (json.status === 'success') {
|
||||||
|
setTimeout(() => {
|
||||||
|
data.showEditModal = false;
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
data.editToastOk = false;
|
||||||
|
data.editToastMsg = '网络异常,请检查连接后重试。';
|
||||||
|
data.editToast = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.editSaving = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
@endsection
|
@endsection
|
||||||
|
|||||||
Reference in New Issue
Block a user