Files
NetworkAuth/web/template/admin/user.html
2025-10-26 01:51:25 +08:00

472 lines
16 KiB
HTML
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.
{{ define "user.html" }}
<style>
/* 基础模块样式 */
.user-module {
margin-bottom: 20px;
}
.user-module .layui-card-header {
font-weight: 600;
transition: background-color 0.3s ease, color 0.3s ease;
}
.module-tabs {
margin-bottom: 20px;
}
.module-tabs .layui-tab-title li {
font-weight: 500;
}
.readonly-field {
cursor: not-allowed !important;
transition: background-color 0.3s ease, color 0.3s ease;
}
/* 浅色模式样式 */
:root {
--user-card-header-bg: #f8f9fa;
--user-card-header-color: #333;
--user-readonly-bg: #f5f5f5;
--user-readonly-color: #666;
--user-card-bg: #ffffff;
--user-card-border: #e6e6e6;
--user-input-bg: #ffffff;
--user-input-border: #d9d9d9;
--user-input-color: #333;
}
/* 深色模式样式 */
@media (prefers-color-scheme: dark) {
:root {
--user-card-header-bg: #2f2f2f;
--user-card-header-color: #e6e6e6;
--user-readonly-bg: #3a3a3a;
--user-readonly-color: #999;
--user-card-bg: #1f1f1f;
--user-card-border: #404040;
--user-input-bg: #2a2a2a;
--user-input-border: #404040;
--user-input-color: #e6e6e6;
}
}
/* 手动深色模式类 */
.dark {
--user-card-header-bg: #2f2f2f;
--user-card-header-color: #e6e6e6;
--user-readonly-bg: #3a3a3a;
--user-readonly-color: #999;
--user-card-bg: #1f1f1f;
--user-card-border: #404040;
--user-input-bg: #2a2a2a;
--user-input-border: #404040;
--user-input-color: #e6e6e6;
}
/* 应用CSS变量到元素 */
.user-module .layui-card-header {
background-color: var(--user-card-header-bg) !important;
color: var(--user-card-header-color) !important;
}
.readonly-field {
background-color: var(--user-readonly-bg) !important;
color: var(--user-readonly-color) !important;
}
.user-module .layui-card {
background-color: var(--user-card-bg);
border-color: var(--user-card-border);
}
.user-module .layui-input {
background-color: var(--user-input-bg);
border-color: var(--user-input-border);
color: var(--user-input-color);
}
/* 确保表单元素在深色模式下的可读性 */
.user-module .layui-form-label {
color: var(--user-card-header-color);
}
/* 按钮在深色模式下的样式调整 */
.user-module .layui-btn-primary {
background-color: var(--user-input-bg);
border-color: var(--user-input-border);
color: var(--user-input-color);
}
.user-module .layui-btn-primary:hover {
background-color: var(--user-readonly-bg);
}
/* 标签页在深色模式下的样式 */
.module-tabs .layui-tab-title {
border-bottom-color: var(--user-card-border);
}
.module-tabs .layui-tab-title li {
color: var(--user-input-color);
}
.module-tabs .layui-tab-title .layui-this {
color: var(--lay-color-primary, #1e9fff);
}
/* 图标颜色适配 */
.user-module .layui-icon {
color: var(--user-card-header-color);
}
</style>
<div class="layui-tab layui-tab-brief module-tabs" lay-filter="userTabs">
<ul class="layui-tab-title">
<li class="layui-this">个人资料</li>
<li>修改密码</li>
<li>修改用户名</li>
</ul>
<div class="layui-tab-content">
<!-- 个人资料模块 -->
<div class="layui-tab-item layui-show">
<div class="layui-card user-module">
<div class="layui-card-header">
<i class="layui-icon layui-icon-user"></i> 个人资料
</div>
<div class="layui-card-body">
<form class="layui-form" id="profileForm" lay-filter="profileForm">
<div class="layui-form-item">
<label class="layui-form-label">UUID</label>
<div class="layui-input-block">
<input type="text" name="uuid" disabled readonly class="layui-input readonly-field" style="font-family: monospace; font-size: 12px;" />
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">用户组</label>
<div class="layui-input-block">
<input type="text" name="role" disabled readonly class="layui-input readonly-field" />
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">用户名</label>
<div class="layui-input-block">
<input type="text" name="username" disabled readonly class="layui-input readonly-field" />
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">创建时间</label>
<div class="layui-input-block">
<input type="text" name="created_at" disabled readonly class="layui-input readonly-field" />
</div>
</div>
</form>
</div>
</div>
</div>
<!-- 修改密码模块 -->
<div class="layui-tab-item">
<div class="layui-card user-module">
<div class="layui-card-header">
<i class="layui-icon layui-icon-password"></i> 修改密码
</div>
<div class="layui-card-body">
<form class="layui-form" id="passwordForm" lay-filter="passwordForm" onsubmit="return false">
<div class="layui-form-item">
<label class="layui-form-label">当前密码</label>
<div class="layui-input-block">
<input type="password" name="old_password" placeholder="请输入当前密码" autocomplete="off" class="layui-input" lay-verify="required" />
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">新密码</label>
<div class="layui-input-block">
<input type="password" name="new_password" placeholder="请输入新密码至少6位" autocomplete="off" class="layui-input" lay-verify="required" />
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">确认密码</label>
<div class="layui-input-block">
<input type="password" name="confirm_password" placeholder="请再次输入新密码" autocomplete="off" class="layui-input" lay-verify="required" />
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="submitPassword">
<i class="layui-icon layui-icon-ok"></i> 修改密码
</button>
<button type="button" id="resetPasswordBtn" class="layui-btn layui-btn-primary">
<i class="layui-icon layui-icon-refresh"></i> 重置
</button>
</div>
</div>
</form>
</div>
</div>
</div>
<!-- 修改用户名模块 -->
<div class="layui-tab-item">
<div class="layui-card user-module">
<div class="layui-card-header">
<i class="layui-icon layui-icon-edit"></i> 修改用户名
</div>
<div class="layui-card-body">
<form class="layui-form" id="usernameForm" lay-filter="usernameForm" onsubmit="return false">
<div class="layui-form-item">
<label class="layui-form-label">当前用户名</label>
<div class="layui-input-block">
<input type="text" name="current_username" disabled readonly class="layui-input readonly-field" />
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">新用户名</label>
<div class="layui-input-block">
<input type="text" name="new_username" placeholder="请输入新用户名" autocomplete="off" class="layui-input" lay-verify="required" />
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">当前密码</label>
<div class="layui-input-block">
<input type="password" name="password" placeholder="请输入当前密码以确认身份" autocomplete="off" class="layui-input" lay-verify="required" />
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="submitUsername">
<i class="layui-icon layui-icon-ok"></i> 修改用户名
</button>
<button type="button" id="resetUsernameBtn" class="layui-btn layui-btn-primary">
<i class="layui-icon layui-icon-refresh"></i> 重置
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
// 使用自执行函数创建局部作用域,避免与其他页面脚本发生全局命名冲突
(() => {
// 工具方法:将数值角色转为中文标签
const roleToText = (role) => {
const r = typeof role === 'string' ? parseInt(role, 10) : role
return r === 0 ? '管理员' : '普通成员'
}
// 格式化时间
const formatTime = (timeStr) => {
if (!timeStr) return ''
const date = new Date(timeStr)
return date.toLocaleString('zh-CN')
}
// 如果未加载 layui则按需加载
const ensureLayui = () => new Promise((resolve) => {
if (window.layui) return resolve(window.layui)
const css = document.createElement('link')
css.rel = 'stylesheet'
css.href = 'https://unpkg.com/layui@2.10.1/dist/css/layui.css'
document.head.appendChild(css)
const script = document.createElement('script')
script.src = 'https://unpkg.com/layui@2.10.1/dist/layui.js'
script.onload = () => resolve(window.layui)
document.head.appendChild(script)
})
// 在确保 Layui 可用后再执行页面逻辑
ensureLayui().then(() => {
layui.use(['form', 'layer', 'element'], () => {
const form = layui.form
const layer = layui.layer
const element = layui.element
// 全局变量
let userProfile = null
// 加载个人资料
const loadProfile = async () => {
try {
const res = await fetch('/admin/api/user/profile')
const data = await res.json()
const ok = (data.success === true) || (data.code === 0)
if (!ok) throw new Error(data.message || data.msg || '加载失败')
userProfile = data.data || {}
// 填充个人资料表单
const profileData = {
...userProfile,
role: roleToText(userProfile.role),
created_at: formatTime(userProfile.created_at)
}
form.val('profileForm', profileData)
// 填充用户名修改表单的当前用户名
form.val('usernameForm', { current_username: userProfile.username })
} catch (e) {
layer.msg(e.message || '加载个人资料失败', { icon: 2 })
}
}
// 修改密码模块
const PasswordModule = {
validate: (fields) => {
const { old_password, new_password, confirm_password } = fields
if (!old_password || !new_password || !confirm_password) {
return { ok: false, msg: '请填写完整的密码信息' }
}
if (new_password.length < 6) {
return { ok: false, msg: '新密码长度不能少于6位' }
}
if (new_password !== confirm_password) {
return { ok: false, msg: '两次输入的新密码不一致' }
}
if (old_password === new_password) {
return { ok: false, msg: '新密码不能与当前密码相同' }
}
return { ok: true }
},
submit: async (fields) => {
const validation = PasswordModule.validate(fields)
if (!validation.ok) {
layer.msg(validation.msg, { icon: 2 })
return false
}
try {
const res = await fetch('/admin/api/user/password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
old_password: fields.old_password,
new_password: fields.new_password,
confirm_password: fields.confirm_password
})
})
const data = await res.json()
const ok = (data.success === true) || (data.code === 0)
if (!ok) throw new Error(data.message || data.msg || '修改密码失败')
// 检查是否需要跳转
if (data.data?.redirect) {
layer.msg('密码修改成功,即将跳转到登录页', { icon: 1, time: 1500 }, () => {
window.location.href = data.data.redirect
})
} else {
// 密码修改成功,不跳转,重置表单
layer.msg('密码修改成功', { icon: 1 })
document.getElementById('passwordForm').reset()
}
} catch (e) {
layer.msg(e.message || '修改密码失败', { icon: 2 })
}
return false
},
reset: () => {
document.getElementById('passwordForm').reset()
layer.msg('表单已重置', { icon: 1 })
}
}
// 修改用户名模块
const UsernameModule = {
validate: (fields) => {
const { new_username, password } = fields
if (!new_username || !password) {
return { ok: false, msg: '请填写新用户名和当前密码' }
}
if (new_username === userProfile?.username) {
return { ok: false, msg: '新用户名不能与当前用户名相同' }
}
if (new_username.length < 3) {
return { ok: false, msg: '用户名长度不能少于3位' }
}
return { ok: true }
},
submit: async (fields) => {
const validation = UsernameModule.validate(fields)
if (!validation.ok) {
layer.msg(validation.msg, { icon: 2 })
return false
}
try {
const res = await fetch('/admin/api/user/profile/update', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: fields.new_username,
old_password: fields.password
})
})
const data = await res.json()
const ok = (data.success === true) || (data.code === 0)
if (!ok) throw new Error(data.message || data.msg || '修改用户名失败')
layer.msg('用户名修改成功', { icon: 1 })
// 重新加载个人资料
await loadProfile()
// 清空表单
UsernameModule.reset()
} catch (e) {
layer.msg(e.message || '修改用户名失败', { icon: 2 })
}
return false
},
reset: () => {
form.val('usernameForm', {
new_username: '',
password: '',
current_username: userProfile?.username || ''
})
layer.msg('表单已重置', { icon: 1 })
}
}
// 绑定表单提交事件
form.on('submit(submitPassword)', (obj) => {
return PasswordModule.submit(obj.field)
})
form.on('submit(submitUsername)', (obj) => {
return UsernameModule.submit(obj.field)
})
// 绑定重置按钮
document.getElementById('resetPasswordBtn')?.addEventListener('click', PasswordModule.reset)
document.getElementById('resetUsernameBtn')?.addEventListener('click', UsernameModule.reset)
// 初始化加载
loadProfile()
})
})
})()
</script>
{{ end }}