409 lines
18 KiB
HTML
409 lines
18 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}个人资料 - 提示词大师{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="container mt-4">
|
||
<div class="row">
|
||
<!-- 侧边栏 -->
|
||
<div class="col-md-3">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h5 class="mb-0">个人中心</h5>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="nav flex-column nav-pills" id="profile-tab" role="tablist">
|
||
<button class="nav-link active" id="profile-info-tab" data-bs-toggle="pill" data-bs-target="#profile-info" type="button" role="tab">
|
||
<i class="fas fa-user me-2"></i>基本信息
|
||
</button>
|
||
<button class="nav-link" id="change-password-tab" data-bs-toggle="pill" data-bs-target="#change-password" type="button" role="tab">
|
||
<i class="fas fa-lock me-2"></i>修改密码
|
||
</button>
|
||
<button class="nav-link" id="usage-stats-tab" data-bs-toggle="pill" data-bs-target="#usage-stats" type="button" role="tab">
|
||
<i class="fas fa-chart-bar me-2"></i>使用统计
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 主内容区 -->
|
||
<div class="col-md-9">
|
||
<div class="tab-content" id="profile-tabContent">
|
||
<!-- 基本信息 -->
|
||
<div class="tab-pane fade show active" id="profile-info" role="tabpanel">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h4 class="mb-0">基本信息</h4>
|
||
</div>
|
||
<div class="card-body">
|
||
<form id="profile-form">
|
||
<div class="row">
|
||
<div class="col-md-6 mb-3">
|
||
<label for="nickname" class="form-label">昵称 <span class="text-danger">*</span></label>
|
||
<input type="text" class="form-control" id="nickname" name="nickname" required>
|
||
</div>
|
||
<div class="col-md-6 mb-3">
|
||
<label for="login_name" class="form-label">用户名</label>
|
||
<input type="text" class="form-control" id="login_name" readonly>
|
||
<small class="text-muted">用户名不可修改</small>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-6 mb-3">
|
||
<label for="email" class="form-label">邮箱</label>
|
||
<input type="email" class="form-control" id="email" name="email">
|
||
</div>
|
||
<div class="col-md-6 mb-3">
|
||
<label for="mobile" class="form-label">手机号</label>
|
||
<input type="tel" class="form-control" id="mobile" name="mobile">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-6 mb-3">
|
||
<label for="sex" class="form-label">性别</label>
|
||
<select class="form-select" id="sex" name="sex">
|
||
<option value="0">保密</option>
|
||
<option value="1">男</option>
|
||
<option value="2">女</option>
|
||
</select>
|
||
</div>
|
||
<div class="col-md-6 mb-3">
|
||
<label for="avatar" class="form-label">头像</label>
|
||
<div class="d-flex align-items-center">
|
||
<img id="avatar-preview" src="/static/images/default-avatar.png" alt="头像" class="rounded-circle me-3" style="width: 60px; height: 60px; object-fit: cover;">
|
||
<button type="button" class="btn btn-outline-primary btn-sm" onclick="document.getElementById('avatar-input').click()">
|
||
更换头像
|
||
</button>
|
||
<input type="file" id="avatar-input" accept="image/*" style="display: none;">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-6 mb-3">
|
||
<label for="created_time" class="form-label">注册时间</label>
|
||
<input type="text" class="form-control" id="created_time" readonly>
|
||
</div>
|
||
<div class="col-md-6 mb-3">
|
||
<label for="last_login" class="form-label">最后登录</label>
|
||
<input type="text" class="form-control" id="last_login" readonly>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="d-flex justify-content-end">
|
||
<button type="submit" class="btn btn-primary">
|
||
<i class="fas fa-save me-2"></i>保存修改
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 修改密码 -->
|
||
<div class="tab-pane fade" id="change-password" role="tabpanel">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h4 class="mb-0">修改密码</h4>
|
||
</div>
|
||
<div class="card-body">
|
||
<form id="password-form">
|
||
<div class="mb-3">
|
||
<label for="old_password" class="form-label">当前密码 <span class="text-danger">*</span></label>
|
||
<input type="password" class="form-control" id="old_password" name="old_password" required>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label for="new_password" class="form-label">新密码 <span class="text-danger">*</span></label>
|
||
<input type="password" class="form-control" id="new_password" name="new_password" required>
|
||
<div class="form-text">密码长度至少6位,建议包含字母、数字和特殊字符</div>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label for="confirm_password" class="form-label">确认新密码 <span class="text-danger">*</span></label>
|
||
<input type="password" class="form-control" id="confirm_password" name="confirm_password" required>
|
||
</div>
|
||
|
||
<div class="d-flex justify-content-end">
|
||
<button type="submit" class="btn btn-warning">
|
||
<i class="fas fa-key me-2"></i>修改密码
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 使用统计 -->
|
||
<div class="tab-pane fade" id="usage-stats" role="tabpanel">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h4 class="mb-0">使用统计</h4>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="row">
|
||
<div class="col-md-4 mb-3">
|
||
<div class="card bg-primary text-white">
|
||
<div class="card-body text-center">
|
||
<h3 id="total-prompts">0</h3>
|
||
<p class="mb-0">生成提示词</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-4 mb-3">
|
||
<div class="card bg-success text-white">
|
||
<div class="card-body text-center">
|
||
<h3 id="total-favorites">0</h3>
|
||
<p class="mb-0">收藏数量</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-4 mb-3">
|
||
<div class="card bg-info text-white">
|
||
<div class="card-body text-center">
|
||
<h3 id="days-active">0</h3>
|
||
<p class="mb-0">活跃天数</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-12">
|
||
<h5>最近活动</h5>
|
||
<div id="recent-activity">
|
||
<p class="text-muted">加载中...</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 成功提示模态框 -->
|
||
<div class="modal fade" id="successModal" tabindex="-1">
|
||
<div class="modal-dialog">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h5 class="modal-title">操作成功</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<p id="success-message">操作已成功完成</p>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">确定</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 错误提示模态框 -->
|
||
<div class="modal fade" id="errorModal" tabindex="-1">
|
||
<div class="modal-dialog">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h5 class="modal-title">操作失败</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<p id="error-message">操作失败,请重试</p>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">确定</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|
||
|
||
{% block scripts %}
|
||
<script>
|
||
// 页面加载完成后执行
|
||
$(document).ready(function() {
|
||
loadProfile();
|
||
loadUsageStats();
|
||
|
||
// 基本信息表单提交
|
||
$('#profile-form').submit(function(e) {
|
||
e.preventDefault();
|
||
updateProfile();
|
||
});
|
||
|
||
// 修改密码表单提交
|
||
$('#password-form').submit(function(e) {
|
||
e.preventDefault();
|
||
changePassword();
|
||
});
|
||
|
||
// 头像上传
|
||
$('#avatar-input').change(function() {
|
||
const file = this.files[0];
|
||
if (file) {
|
||
const reader = new FileReader();
|
||
reader.onload = function(e) {
|
||
$('#avatar-preview').attr('src', e.target.result);
|
||
};
|
||
reader.readAsDataURL(file);
|
||
}
|
||
});
|
||
});
|
||
|
||
// 加载个人资料
|
||
function loadProfile() {
|
||
$.get('/api/profile')
|
||
.done(function(response) {
|
||
if (response.success) {
|
||
const user = response.data;
|
||
$('#nickname').val(user.nickname || '');
|
||
$('#login_name').val(user.login_name || '');
|
||
$('#email').val(user.email || '');
|
||
$('#mobile').val(user.mobile || '');
|
||
$('#sex').val(user.sex || 0);
|
||
$('#created_time').val(user.created_time || '');
|
||
$('#last_login').val(user.last_login || '');
|
||
|
||
if (user.avatar) {
|
||
$('#avatar-preview').attr('src', user.avatar);
|
||
}
|
||
} else {
|
||
showError(response.message || '加载个人资料失败');
|
||
}
|
||
})
|
||
.fail(function() {
|
||
showError('加载个人资料失败');
|
||
});
|
||
}
|
||
|
||
// 更新个人资料
|
||
function updateProfile() {
|
||
const formData = {
|
||
nickname: $('#nickname').val(),
|
||
email: $('#email').val(),
|
||
mobile: $('#mobile').val(),
|
||
sex: parseInt($('#sex').val())
|
||
};
|
||
|
||
$.ajax({
|
||
url: '/api/profile',
|
||
method: 'PUT',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify(formData)
|
||
})
|
||
.done(function(response) {
|
||
if (response.success) {
|
||
showSuccess('个人资料更新成功');
|
||
// 更新session中的昵称
|
||
if (formData.nickname) {
|
||
// 这里可以更新页面上的用户昵称显示
|
||
}
|
||
} else {
|
||
showError(response.message || '更新失败');
|
||
}
|
||
})
|
||
.fail(function() {
|
||
showError('更新失败,请重试');
|
||
});
|
||
}
|
||
|
||
// 修改密码
|
||
function changePassword() {
|
||
const oldPassword = $('#old_password').val();
|
||
const newPassword = $('#new_password').val();
|
||
const confirmPassword = $('#confirm_password').val();
|
||
|
||
if (newPassword !== confirmPassword) {
|
||
showError('两次输入的新密码不一致');
|
||
return;
|
||
}
|
||
|
||
if (newPassword.length < 6) {
|
||
showError('新密码长度至少6位');
|
||
return;
|
||
}
|
||
|
||
$.ajax({
|
||
url: '/api/change-password',
|
||
method: 'POST',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify({
|
||
old_password: oldPassword,
|
||
new_password: newPassword
|
||
})
|
||
})
|
||
.done(function(response) {
|
||
if (response.success) {
|
||
showSuccess('密码修改成功,请重新登录');
|
||
// 清空表单
|
||
$('#password-form')[0].reset();
|
||
// 可以选择跳转到登录页面
|
||
setTimeout(function() {
|
||
window.location.href = '/login';
|
||
}, 2000);
|
||
} else {
|
||
showError(response.message || '密码修改失败');
|
||
}
|
||
})
|
||
.fail(function() {
|
||
showError('密码修改失败,请重试');
|
||
});
|
||
}
|
||
|
||
// 加载使用统计
|
||
function loadUsageStats() {
|
||
$.get('/api/profile/stats')
|
||
.done(function(response) {
|
||
if (response.success) {
|
||
const data = response.data;
|
||
$('#total-prompts').text(data.total_prompts || 0);
|
||
$('#total-favorites').text(data.total_favorites || 0);
|
||
$('#days-active').text(data.days_active || 0);
|
||
|
||
// 加载最近活动
|
||
let activityHtml = '<div class="list-group">';
|
||
if (data.recent_activities && data.recent_activities.length > 0) {
|
||
data.recent_activities.forEach(activity => {
|
||
activityHtml += `
|
||
<div class="list-group-item">
|
||
<div class="d-flex justify-content-between">
|
||
<span>${activity.type}: ${activity.content}</span>
|
||
<small class="text-muted">${activity.time}</small>
|
||
</div>
|
||
</div>
|
||
`;
|
||
});
|
||
} else {
|
||
activityHtml += '<div class="list-group-item"><span class="text-muted">暂无活动记录</span></div>';
|
||
}
|
||
activityHtml += '</div>';
|
||
$('#recent-activity').html(activityHtml);
|
||
} else {
|
||
$('#recent-activity').html('<p class="text-danger">加载统计信息失败</p>');
|
||
}
|
||
})
|
||
.fail(function() {
|
||
$('#recent-activity').html('<p class="text-danger">加载统计信息失败</p>');
|
||
});
|
||
}
|
||
|
||
// 显示成功提示
|
||
function showSuccess(message) {
|
||
$('#success-message').text(message);
|
||
new bootstrap.Modal(document.getElementById('successModal')).show();
|
||
}
|
||
|
||
// 显示错误提示
|
||
function showError(message) {
|
||
$('#error-message').text(message);
|
||
new bootstrap.Modal(document.getElementById('errorModal')).show();
|
||
}
|
||
</script>
|
||
{% endblock %}
|