394 lines
19 KiB
HTML
394 lines
19 KiB
HTML
<div class="layui-fluid layui-container">
|
||
<div class="layui-col-space15">
|
||
<div class="layui-col-md10 layui-col-md-offset1">
|
||
<h1 data-i18n="PersonalCenter">个人中心</h1>
|
||
</div>
|
||
</div>
|
||
<div class="layui-col-space15">
|
||
<div class="layui-col-md10 layui-col-md-offset1">
|
||
<div class="layui-card layui-card-round">
|
||
<div class="layui-card-header" data-i18n="PersonalInformation">
|
||
个人信息
|
||
</div>
|
||
<div class="layui-card-body">
|
||
<div class="layui-col-md4">
|
||
<div class="avatar-container">
|
||
<img src="{{ url_for('UGM.UGM_Query_GetELTUserAvatar') }}"
|
||
class="layui-circle avatar-img" id="Head">
|
||
<div class="avatar-overlay" id="UpdateHead" data-i18n="ModifyPicture">修改头像</div>
|
||
<input type="file" id="fileInput" style="display: none;" accept="image/*">
|
||
</div>
|
||
</div>
|
||
<div class="layui-col-md7" style="margin: 30px;">
|
||
<table class="layui-table">
|
||
<tbody>
|
||
<tr>
|
||
<th><span data-i18n="Name">名称</span>:</th>
|
||
<td name="UserName"></td>
|
||
</tr>
|
||
<tr>
|
||
<th><span data-i18n="IdentificationCode">身份标识代码(UUID)</span>:</th>
|
||
<td name="UserUUID"></td>
|
||
</tr>
|
||
<tr>
|
||
<th><span data-i18n="PersonalSignature">个人简介</span>:</th>
|
||
<td name="UserPersonalSignature"></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 新增双因素认证模块 -->
|
||
<div class="layui-col-space15">
|
||
<div class="layui-col-md10 layui-col-md-offset1">
|
||
<div class="layui-card layui-card-round">
|
||
<details>
|
||
<summary class="collapse-name" tabindex="-1">
|
||
<div class="layui-card-header">
|
||
<span data-i18n="TwoFactorAuthentication">双因素认证</span>
|
||
<i class="show-icon iconfont"></i>
|
||
</div>
|
||
</summary>
|
||
<div class="layui-card-body">
|
||
<div class="layui-row">
|
||
<div class="layui-col-md12">
|
||
<button class="layui-btn layui-btn-normal" id="showQRCodeBtn">
|
||
<i class="layui-icon"></i> 获取认证二维码
|
||
</button>
|
||
|
||
<div class="layui-form-item" style="margin-top: 20px;">
|
||
<label class="layui-form-label">6位验证码</label>
|
||
<div class="layui-input-inline">
|
||
<input type="text" id="authCodeInput" placeholder="请输入6位数字验证码"
|
||
class="layui-input" maxlength="6" oninput="this.value=this.value.replace(/\D/g,'')">
|
||
</div>
|
||
<div class="layui-input-inline">
|
||
<button class="layui-btn layui-btn-primary" id="verifyCodeBtn">
|
||
<i class="layui-icon"></i> 验证
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</details>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="layui-col-space15">
|
||
<div class="layui-col-md10 layui-col-md-offset1">
|
||
<div class="layui-card layui-card-round">
|
||
<details>
|
||
<summary class="collapse-name" tabindex="-1">
|
||
<div class="layui-card-header">
|
||
<span data-i18n="PersonalInformation">个人信息</span>
|
||
<i class="show-icon iconfont"></i>
|
||
</div>
|
||
</summary>
|
||
<div class="layui-card-body">
|
||
<ul class="layui-row">
|
||
<li class="layui-col-md12">
|
||
<table class="layui-table">
|
||
<tbody>
|
||
<tr>
|
||
<th><span data-i18n="Permission">权限</span>:</th>
|
||
<td name="UserPermission"></td>
|
||
</tr>
|
||
<tr>
|
||
<th><span data-i18n="PermissionDescription">权限描述</span>:</th>
|
||
<td name="UserStrPermission"></td>
|
||
</tr>
|
||
<tr>
|
||
<th><span data-i18n="Office">职务</span>:</th>
|
||
<td name="UserJob"></td>
|
||
</tr>
|
||
<tr>
|
||
<th><span data-i18n="Position">职务情况</span>:</th>
|
||
<td name="UserPosition"></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</details>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="layui-col-space15">
|
||
<div class="layui-col-md10 layui-col-md-offset1">
|
||
<div class="layui-card layui-card-round">
|
||
<details>
|
||
<summary class="collapse-name" tabindex="-1">
|
||
<div class="layui-card-header">
|
||
<span data-i18n="PointsInformation">积分信息</span>
|
||
<i class="show-icon iconfont"></i>
|
||
</div>
|
||
</summary>
|
||
<div class="layui-card-body">
|
||
<table class="layui-table">
|
||
<tbody>
|
||
<tr>
|
||
<th><span data-i18n="Integral">积分</span>:</th>
|
||
<td name="UserMoneyIntegral"></td>
|
||
</tr>
|
||
<tr>
|
||
<th><span data-i18n="LightCoin">光币</span>:</th>
|
||
<td name="UserMoneyLightCoin"></td>
|
||
</tr>
|
||
<tr>
|
||
<th><span data-i18n="BrightCoin">星光币</span>:</th>
|
||
<td name="UserMoneyBrightCoin"></td>
|
||
</tr>
|
||
<tr>
|
||
<th><span data-i18n="DarkCoin">暗黑币</span>:</th>
|
||
<td name="UserMoneyDarkCoin"></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</details>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="layui-col-space15">
|
||
<div class="layui-col-md1 layui-col-md-offset5">
|
||
</div>
|
||
</div>
|
||
<!--<div class="layui-col-md12">
|
||
<div class="layui-col-md6">
|
||
<div class="layui-card layui-card-round">
|
||
<div class="layui-card-header">修改密码</div>
|
||
<div class="layui-card-body">
|
||
<form class="layui-form" method="post" action="https://ugm.gvsds.com/ReCookiesUserPasswd">
|
||
<div class="layui-form-item">
|
||
<label for="old_passwd" class="layui-form-label">
|
||
<span class="x-red"></span>旧密码</label>
|
||
<div class="layui-input-inline">
|
||
<input type="text" id="old_passwd" name="old_passwd" required=""
|
||
lay-verify="nikename" autocomplete="off" class="layui-input">
|
||
</div>
|
||
</div>
|
||
<div class="layui-form-item">
|
||
<label for="passwd" class="layui-form-label">
|
||
<span class="x-red"></span>新密码</label>
|
||
<div class="layui-input-inline">
|
||
<input type="text" id="passwd1" name="passwd1" required="" lay-verify="nikename"
|
||
autocomplete="off" class="layui-input">
|
||
</div>
|
||
</div>
|
||
<div class="layui-form-item">
|
||
<label for="passwd2" class="layui-form-label">
|
||
<span class="x-red"></span>确认密码</label>
|
||
<div class="layui-input-inline">
|
||
<input type="text" id="passwd2" name="passwd2" required="" lay-verify="nikename"
|
||
autocomplete="off" class="layui-input">
|
||
</div>
|
||
</div>
|
||
<div class="layui-form-item">
|
||
<label for="L_repass" class="layui-form-label"></label>
|
||
<input type="submit" class="layui-btn" lay-filter="add" lay-submit="" text="修改" />
|
||
</div>
|
||
</form>
|
||
<!--<div class="layui-upload">
|
||
<button type="button" class="layui-btn" id="test1">上传图片</button>
|
||
<div class="layui-upload-list">
|
||
<img class="layui-upload-img" id="demo1" width="200px" height="200px"
|
||
src="{{ url_for('UGM.UGM_Query_GetELTUserAvatar') }}">
|
||
<p id="demoText"></p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>-->
|
||
<script>
|
||
TempLate("/API/User/UserCenterCard");
|
||
TempLate("/API/Money");
|
||
document.getElementById('UpdateHead').addEventListener('click', function () {
|
||
document.getElementById('fileInput').click();
|
||
});
|
||
document.getElementById('fileInput').addEventListener('change', async function (e) {
|
||
var loadIndex = layer.load(2);
|
||
try {
|
||
const file = e.target.files[0];
|
||
if (!file) return;
|
||
if (file.size > 5 * 1024 * 1024) {
|
||
throw new Error(i18n('NoMore5MB'));
|
||
}
|
||
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
|
||
if (!allowedTypes.includes(file.type)) {
|
||
throw new Error(i18n('OnlyJPEGPNGIF'));
|
||
}
|
||
await uploadFile(file);
|
||
} catch (error) {
|
||
Toast.error(i18n('ModifyPictureFailed'), error.message, 5000);
|
||
e.target.value = '';
|
||
}
|
||
reloadImage("Head", "{{ url_for('UGM.UGM_Query_GetELTUserAvatar') }}");
|
||
layer.close(loadIndex);
|
||
});
|
||
|
||
async function uploadFile(file) {
|
||
try {
|
||
const formData = new FormData();
|
||
formData.append('file', file);
|
||
const headers = {};
|
||
const response = await fetch("{{ url_for('UGM.UGM_Modify_ModifyELTUserAvatar') }}", {
|
||
method: 'POST',
|
||
body: formData,
|
||
headers: headers,
|
||
credentials: 'include'
|
||
});
|
||
if (!response.ok) {
|
||
const errorData = await response.json().catch(() => ({}));
|
||
throw new Error(errorData.message || i18n('ServerBackStatus') + `: ${response.status}`);
|
||
}
|
||
const data = await response.json();
|
||
if (data.code == 0) {
|
||
Toast.success(i18n('ModifyPictureSuccess'), data.msg, 5000);
|
||
} else {
|
||
Toast.error(i18n('ModifyPictureFailed'), data.msg, 5000);
|
||
}
|
||
return data;
|
||
} catch (error) {
|
||
Toast.error(i18n('ModifyPictureFailed'), error, 5000);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
function reloadImage(imgId, imgUrl) {
|
||
document.getElementById(imgId).src = imgUrl + '?t=' + new Date().getTime();
|
||
window.parent.document.getElementById('side-nav-img').src = imgUrl + '?t=' + new Date().getTime();
|
||
}
|
||
|
||
// 双因素认证相关功能
|
||
layui.use(['layer', 'form'], function() {
|
||
var layer = layui.layer;
|
||
var form = layui.form;
|
||
|
||
// 显示二维码弹窗
|
||
document.getElementById('showQRCodeBtn').addEventListener('click', async function() {
|
||
var loadIndex = layer.load(2);
|
||
try {
|
||
const response = await fetch('/API/TwoFactorAuthentication/QR', {
|
||
method: 'GET',
|
||
credentials: 'include'
|
||
});
|
||
if (!response.ok) {
|
||
throw new Error(`服务器返回错误: ${response.status}`);
|
||
}
|
||
const contentType = response.headers.get('content-type');
|
||
let qrContent = '';
|
||
if (contentType.includes('image')) {
|
||
const blob = await response.blob();
|
||
const imageUrl = URL.createObjectURL(blob);
|
||
qrContent = `<img src="${imageUrl}" style="max-width: 300px; max-height: 300px;" />`;
|
||
} else if (contentType.includes('json')) {
|
||
const jsonData = await response.json();
|
||
if (jsonData.code === 0 && jsonData.qrUrl) {
|
||
qrContent = `<img src="${jsonData.qrUrl}" style="max-width: 300px; max-height: 300px;" />`;
|
||
} else {
|
||
qrContent = `<div style="text-align: center; padding: 20px;">
|
||
<p style="color: red;">${jsonData.msg || '获取二维码失败'}</p>
|
||
</div>`;
|
||
}
|
||
} else {
|
||
const text = await response.text();
|
||
qrContent = `<div style="text-align: center; padding: 20px;">
|
||
<p>${text}</p>
|
||
</div>`;
|
||
}
|
||
layer.close(loadIndex);
|
||
layer.open({
|
||
type: 1,
|
||
title: '双因素认证二维码',
|
||
area: ['400px', '500px'],
|
||
shade: 0.3,
|
||
content: `<div style="padding: 20px; text-align: center;">
|
||
${qrContent}
|
||
<p style="margin-top: 15px; font-size: 12px; color: #666;">
|
||
请使用认证APP扫描此二维码
|
||
</p>
|
||
</div>`,
|
||
btn: ['关闭'],
|
||
btnAlign: 'c',
|
||
yes: function(index) {
|
||
layer.close(index);
|
||
}
|
||
});
|
||
} catch (error) {
|
||
layer.close(loadIndex);
|
||
layer.msg(`获取二维码失败: ${error.message}`, {
|
||
icon: 2,
|
||
time: 3000
|
||
});
|
||
console.error('获取二维码错误:', error);
|
||
}
|
||
});
|
||
async function verifyAuthCode() {
|
||
const code = document.getElementById('authCodeInput').value.trim();
|
||
if (code.length !== 6 || isNaN(code)) {
|
||
layer.msg('请输入有效的6位数字验证码', {
|
||
icon: 2,
|
||
time: 2000
|
||
});
|
||
return;
|
||
}
|
||
var loadIndex = layer.load(2);
|
||
try {
|
||
const response = await fetch(`/API/TwoFactorAuthentication/Setup?token=${encodeURIComponent(code)}`, {
|
||
method: 'GET',
|
||
credentials: 'include',
|
||
headers: {
|
||
'Accept': 'application/json'
|
||
}
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
// 关闭加载层
|
||
layer.close(loadIndex);
|
||
|
||
// 处理响应
|
||
if (result.code === 0) {
|
||
layer.msg(result.msg || '验证成功', {
|
||
icon: 1,
|
||
time: 2000
|
||
});
|
||
// 清空输入框
|
||
document.getElementById('authCodeInput').value = '';
|
||
} else {
|
||
layer.msg(result.msg || '验证失败', {
|
||
icon: 2,
|
||
time: 3000
|
||
});
|
||
}
|
||
|
||
} catch (error) {
|
||
layer.close(loadIndex);
|
||
layer.msg(`验证失败: ${error.message}`, {
|
||
icon: 2,
|
||
time: 3000
|
||
});
|
||
console.error('验证验证码错误:', error);
|
||
}
|
||
}
|
||
|
||
// 验证按钮点击事件
|
||
document.getElementById('verifyCodeBtn').addEventListener('click', verifyAuthCode);
|
||
|
||
// 输入框回车事件
|
||
document.getElementById('authCodeInput').addEventListener('keypress', function(e) {
|
||
if (e.key === 'Enter') {
|
||
verifyAuthCode();
|
||
}
|
||
});
|
||
});
|
||
</script>
|
||
</div> |