
功能特性: - JWT用户认证系统 - 日报CRUD管理 - 三级权限控制 - 多维度搜索过滤 - 统计分析功能 - 评论互动系统 - 响应式Cool Admin界面 - 暗色主题支持 技术栈: - 后端:Django 4.2.7 + DRF + SimpleJWT - 前端:Vue 3 + Element Plus + Pinia - 数据库:SQLite/PostgreSQL - 部署:Docker + Nginx 包含内容: - 完整的后端API代码 - 现代化前端界面 - 数据库迁移文件 - 部署脚本和文档 - 演示页面和测试工具
378 lines
14 KiB
HTML
378 lines
14 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>API测试页面 - 企业级日报系统</title>
|
||
<style>
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||
margin: 0;
|
||
padding: 20px;
|
||
background: #f5f7fa;
|
||
}
|
||
.container {
|
||
max-width: 800px;
|
||
margin: 0 auto;
|
||
background: white;
|
||
border-radius: 8px;
|
||
padding: 30px;
|
||
box-shadow: 0 2px 12px rgba(0,0,0,0.1);
|
||
}
|
||
h1 {
|
||
color: #303133;
|
||
text-align: center;
|
||
margin-bottom: 30px;
|
||
}
|
||
.test-section {
|
||
margin-bottom: 30px;
|
||
padding: 20px;
|
||
border: 1px solid #e4e7ed;
|
||
border-radius: 6px;
|
||
background: #fafafa;
|
||
}
|
||
.test-title {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: #409eff;
|
||
margin-bottom: 15px;
|
||
}
|
||
.test-button {
|
||
background: #409eff;
|
||
color: white;
|
||
border: none;
|
||
padding: 10px 20px;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
margin-right: 10px;
|
||
margin-bottom: 10px;
|
||
}
|
||
.test-button:hover {
|
||
background: #66b1ff;
|
||
}
|
||
.test-button.success {
|
||
background: #67c23a;
|
||
}
|
||
.test-button.success:hover {
|
||
background: #85ce61;
|
||
}
|
||
.result {
|
||
margin-top: 15px;
|
||
padding: 15px;
|
||
border-radius: 4px;
|
||
font-family: monospace;
|
||
font-size: 14px;
|
||
white-space: pre-wrap;
|
||
max-height: 200px;
|
||
overflow-y: auto;
|
||
}
|
||
.result.success {
|
||
background: #f0f9ff;
|
||
border: 1px solid #b3d8ff;
|
||
color: #0066cc;
|
||
}
|
||
.result.error {
|
||
background: #fef0f0;
|
||
border: 1px solid #fbc4c4;
|
||
color: #f56c6c;
|
||
}
|
||
.status {
|
||
display: inline-block;
|
||
padding: 4px 8px;
|
||
border-radius: 3px;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
margin-left: 10px;
|
||
}
|
||
.status.online {
|
||
background: #67c23a;
|
||
color: white;
|
||
}
|
||
.status.offline {
|
||
background: #f56c6c;
|
||
color: white;
|
||
}
|
||
.login-form {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 15px;
|
||
margin-bottom: 15px;
|
||
}
|
||
.form-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.form-group label {
|
||
margin-bottom: 5px;
|
||
font-weight: 500;
|
||
}
|
||
.form-group input {
|
||
padding: 8px;
|
||
border: 1px solid #dcdfe6;
|
||
border-radius: 4px;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1>🧪 API测试页面</h1>
|
||
|
||
<!-- 服务状态检查 -->
|
||
<div class="test-section">
|
||
<div class="test-title">🔍 服务状态检查</div>
|
||
<button class="test-button" onclick="checkBackendStatus()">检查后端服务</button>
|
||
<button class="test-button" onclick="checkFrontendStatus()">检查前端服务</button>
|
||
<div id="statusResult" class="result" style="display: none;"></div>
|
||
</div>
|
||
|
||
<!-- API测试 -->
|
||
<div class="test-section">
|
||
<div class="test-title">🔐 用户认证测试</div>
|
||
<div class="login-form">
|
||
<div class="form-group">
|
||
<label>用户名:</label>
|
||
<input type="text" id="username" value="admin" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label>密码:</label>
|
||
<input type="password" id="password" value="admin123456" />
|
||
</div>
|
||
</div>
|
||
<button class="test-button" onclick="testLogin()">测试登录</button>
|
||
<button class="test-button success" onclick="testGetProfile()">获取用户信息</button>
|
||
<div id="authResult" class="result" style="display: none;"></div>
|
||
</div>
|
||
|
||
<!-- 日报API测试 -->
|
||
<div class="test-section">
|
||
<div class="test-title">📝 日报API测试</div>
|
||
<button class="test-button" onclick="testGetReports()">获取日报列表</button>
|
||
<button class="test-button" onclick="testCreateReport()">创建测试日报</button>
|
||
<button class="test-button" onclick="testGetStats()">获取统计数据</button>
|
||
<div id="reportsResult" class="result" style="display: none;"></div>
|
||
</div>
|
||
|
||
<!-- 快速链接 -->
|
||
<div class="test-section">
|
||
<div class="test-title">🔗 快速链接</div>
|
||
<a href="http://localhost:8000/admin/" target="_blank">
|
||
<button class="test-button">Django管理后台</button>
|
||
</a>
|
||
<a href="http://localhost:8000/api/" target="_blank">
|
||
<button class="test-button">API根目录</button>
|
||
</a>
|
||
<a href="http://localhost:3000" target="_blank">
|
||
<button class="test-button success">前端应用</button>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
let authToken = null;
|
||
|
||
// 显示结果
|
||
function showResult(elementId, content, isSuccess = true) {
|
||
const element = document.getElementById(elementId);
|
||
element.style.display = 'block';
|
||
element.className = `result ${isSuccess ? 'success' : 'error'}`;
|
||
element.textContent = content;
|
||
}
|
||
|
||
// 检查后端服务状态
|
||
async function checkBackendStatus() {
|
||
try {
|
||
const response = await fetch('http://localhost:8000/api/auth/login/', {
|
||
method: 'OPTIONS'
|
||
});
|
||
showResult('statusResult', '✅ 后端服务运行正常\n状态码: ' + response.status + '\n地址: http://localhost:8000');
|
||
} catch (error) {
|
||
showResult('statusResult', '❌ 后端服务连接失败\n错误: ' + error.message + '\n\n请确保Django服务器已启动:\ncd backend && python manage.py runserver', false);
|
||
}
|
||
}
|
||
|
||
// 检查前端服务状态
|
||
async function checkFrontendStatus() {
|
||
try {
|
||
const response = await fetch('http://localhost:3000/', {
|
||
method: 'GET',
|
||
mode: 'no-cors'
|
||
});
|
||
showResult('statusResult', '✅ 前端服务运行正常\n地址: http://localhost:3000');
|
||
} catch (error) {
|
||
showResult('statusResult', '❌ 前端服务连接失败\n错误: ' + error.message + '\n\n请确保Vue服务器已启动:\ncd frontend && npm run serve', false);
|
||
}
|
||
}
|
||
|
||
// 测试登录
|
||
async function testLogin() {
|
||
const username = document.getElementById('username').value;
|
||
const password = document.getElementById('password').value;
|
||
|
||
try {
|
||
const response = await fetch('http://localhost:8000/api/auth/login/', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ username, password })
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (response.ok) {
|
||
authToken = data.tokens.access;
|
||
showResult('authResult',
|
||
'✅ 登录成功!\n' +
|
||
'用户: ' + data.user.username + '\n' +
|
||
'姓名: ' + (data.user.full_name || '未设置') + '\n' +
|
||
'权限: ' + (data.user.is_staff ? '管理员' : '普通用户') + '\n' +
|
||
'Token: ' + data.tokens.access.substring(0, 50) + '...'
|
||
);
|
||
} else {
|
||
showResult('authResult', '❌ 登录失败\n' + JSON.stringify(data, null, 2), false);
|
||
}
|
||
} catch (error) {
|
||
showResult('authResult', '❌ 登录请求失败\n错误: ' + error.message, false);
|
||
}
|
||
}
|
||
|
||
// 测试获取用户信息
|
||
async function testGetProfile() {
|
||
if (!authToken) {
|
||
showResult('authResult', '❌ 请先登录获取Token', false);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch('http://localhost:8000/api/auth/profile/', {
|
||
headers: {
|
||
'Authorization': 'Bearer ' + authToken
|
||
}
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (response.ok) {
|
||
showResult('authResult',
|
||
'✅ 获取用户信息成功!\n' +
|
||
JSON.stringify(data, null, 2)
|
||
);
|
||
} else {
|
||
showResult('authResult', '❌ 获取用户信息失败\n' + JSON.stringify(data, null, 2), false);
|
||
}
|
||
} catch (error) {
|
||
showResult('authResult', '❌ 请求失败\n错误: ' + error.message, false);
|
||
}
|
||
}
|
||
|
||
// 测试获取日报列表
|
||
async function testGetReports() {
|
||
if (!authToken) {
|
||
showResult('reportsResult', '❌ 请先登录获取Token', false);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch('http://localhost:8000/api/reports/', {
|
||
headers: {
|
||
'Authorization': 'Bearer ' + authToken
|
||
}
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (response.ok) {
|
||
showResult('reportsResult',
|
||
'✅ 获取日报列表成功!\n' +
|
||
'总数: ' + (data.count || 0) + '\n' +
|
||
'结果: ' + JSON.stringify(data, null, 2).substring(0, 500) + '...'
|
||
);
|
||
} else {
|
||
showResult('reportsResult', '❌ 获取日报列表失败\n' + JSON.stringify(data, null, 2), false);
|
||
}
|
||
} catch (error) {
|
||
showResult('reportsResult', '❌ 请求失败\n错误: ' + error.message, false);
|
||
}
|
||
}
|
||
|
||
// 测试创建日报
|
||
async function testCreateReport() {
|
||
if (!authToken) {
|
||
showResult('reportsResult', '❌ 请先登录获取Token', false);
|
||
return;
|
||
}
|
||
|
||
const reportData = {
|
||
report_date: new Date().toISOString().split('T')[0],
|
||
work_summary: '今天完成了API测试功能的开发,包括前端界面和后端接口的测试。',
|
||
next_day_plan: '明天将继续优化系统性能,添加更多的测试用例。',
|
||
is_draft: false
|
||
};
|
||
|
||
try {
|
||
const response = await fetch('http://localhost:8000/api/reports/', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Authorization': 'Bearer ' + authToken,
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(reportData)
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (response.ok) {
|
||
showResult('reportsResult',
|
||
'✅ 创建日报成功!\n' +
|
||
'ID: ' + data.id + '\n' +
|
||
'日期: ' + data.report_date + '\n' +
|
||
'状态: ' + (data.is_draft ? '草稿' : '已发布')
|
||
);
|
||
} else {
|
||
showResult('reportsResult', '❌ 创建日报失败\n' + JSON.stringify(data, null, 2), false);
|
||
}
|
||
} catch (error) {
|
||
showResult('reportsResult', '❌ 请求失败\n错误: ' + error.message, false);
|
||
}
|
||
}
|
||
|
||
// 测试获取统计数据
|
||
async function testGetStats() {
|
||
if (!authToken) {
|
||
showResult('reportsResult', '❌ 请先登录获取Token', false);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch('http://localhost:8000/api/stats/', {
|
||
headers: {
|
||
'Authorization': 'Bearer ' + authToken
|
||
}
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (response.ok) {
|
||
showResult('reportsResult',
|
||
'✅ 获取统计数据成功!\n' +
|
||
'总日报数: ' + data.total_reports + '\n' +
|
||
'本月日报: ' + data.this_month_reports + '\n' +
|
||
'本周日报: ' + data.this_week_reports + '\n' +
|
||
'完成率: ' + data.completion_rate + '%'
|
||
);
|
||
} else {
|
||
showResult('reportsResult', '❌ 获取统计数据失败\n' + JSON.stringify(data, null, 2), false);
|
||
}
|
||
} catch (error) {
|
||
showResult('reportsResult', '❌ 请求失败\n错误: ' + error.message, false);
|
||
}
|
||
}
|
||
|
||
// 页面加载完成后自动检查服务状态
|
||
window.onload = function() {
|
||
setTimeout(checkBackendStatus, 1000);
|
||
};
|
||
</script>
|
||
</body>
|
||
</html>
|