Files
ASP.NET-CORE-web-test/HTML/idexe.html
2025-10-10 16:02:38 +08:00

581 lines
23 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.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ASP.NET Core Minimal API CRUD Test</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: #f4f4f4;
color: #333;
}
h1, h2, h3 {
color: #0056b3;
}
.container {
display: flex;
gap: 20px;
flex-wrap: wrap;
}
.entity-section {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
padding: 20px;
flex: 1;
min-width: 450px;
box-sizing: border-box;
}
.operation-section {
padding: 15px;
border: 1px solid #eee;
border-radius: 5px;
margin-bottom: 15px;
background-color: #f9f9f9;
}
.operation-section h4 {
margin-top: 0;
color: #333;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="text"],
input[type="number"],
input[type="email"],
input[type="password"],
input[type="checkbox"],
textarea {
width: calc(100% - 22px);
padding: 8px;
margin-bottom: 10px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
input[type="checkbox"] {
width: auto;
margin-right: 5px;
}
button {
background-color: #007bff;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.2s ease;
margin-right: 10px;
}
button:hover {
background-color: #0056b3;
}
.result-box {
background-color: #e9ecef;
border: 1px solid #ced4da;
padding: 15px;
margin-top: 15px;
border-radius: 5px;
white-space: pre-wrap;
font-family: monospace;
max-height: 300px;
overflow-y: auto;
}
.error {
color: red;
font-weight: bold;
}
.success {
color: green;
font-weight: bold;
}
.loading {
color: gray;
font-style: italic;
}
ul {
list-style-type: none;
padding: 0;
}
li {
background-color: #f0f0f0;
margin-bottom: 5px;
padding: 8px;
border-radius: 3px;
border-left: 5px solid #007bff;
}
</style>
</head>
<body>
<h1>ASP.NET Core Minimal API CRUD 测试</h1>
<p>确保您的 ASP.NET Core 应用正在运行,并监听以下基准 URL。</</p>
<div class="container">
<!-- Todo Section -->
<div class="entity-section">
<h2>待办事项 (Todos) CRUD</h2>
<!-- 获取所有 Todo -->
<div class="operation-section">
<h4>获取所有待办事项</h4>
<button onclick="getAllTodos()">获取所有 Todo</button>
<div id="allTodosResult" class="result-box"></div>
</div>
<!-- 根据 ID 获取 Todo -->
<div class="operation-section">
<h4>根据 ID 获取待办事项</h4>
<label for="getTodoId">待办事项 ID:</label>
<input type="number" id="getTodoId" value="1">
<button onclick="getTodoById()">获取 Todo</button>
<div id="singleTodoResult" class="result-box"></div>
</div>
<!-- 创建 Todo -->
<div class="operation-section">
<h4>创建待办事项</h4>
<label for="createTodoTitle">标题:</label>
<input type="text" id="createTodoTitle" placeholder="新的待办事项标题">
<label for="createTodoIsCompleted">已完成:</label>
<input type="checkbox" id="createTodoIsCompleted">
<label for="createTodoUserId">用户ID (关联的用户):</label>
<input type="number" id="createTodoUserId" value="1" placeholder="例如: 1">
<button onclick="createTodo()">创建 Todo</button>
<div id="createTodoResult" class="result-box"></div>
</div>
<!-- 更新 Todo -->
<div class="operation-section">
<h4>更新待办事项</h4>
<label for="updateTodoId">待办事项 ID:</label>
<input type="number" id="updateTodoId" value="1">
<label for="updateTodoTitle">新标题:</label>
<input type="text" id="updateTodoTitle" placeholder="更新后的待办事项标题">
<label for="updateTodoIsCompleted">已完成:</label>
<input type="checkbox" id="updateTodoIsCompleted">
<label for="updateTodoUserId">用户ID (关联的用户):</label>
<input type="number" id="updateTodoUserId" value="1" placeholder="例如: 1">
<button onclick="updateTodo()">更新 Todo</button>
<div id="updateTodoResult" class="result-box"></div>
</div>
<!-- 删除 Todo -->
<div class="operation-section">
<h4>删除待办事项</h4>
<label for="deleteTodoId">待办事项 ID:</label>
<input type="number" id="deleteTodoId" value="1">
<button onclick="deleteTodo()">删除 Todo</button>
<div id="deleteTodoResult" class="result-box"></div>
</div>
</div>
<!-- User Section -->
<div class="entity-section">
<h2>用户 (Users) CRUD</h2>
<!-- 获取所有 User -->
<div class="operation-section">
<h4>获取所有用户</h4>
<button onclick="getAllUsers()">获取所有 User</button>
<div id="allUsersResult" class="result-box"></div>
</div>
<!-- 根据 ID 获取 User -->
<div class="operation-section">
<h4>根据 ID 获取用户</h4>
<label for="getUserId">用户 ID:</label>
<input type="number" id="getUserId" value="1">
<button onclick="getUserById()">获取 User</button>
<div id="singleUserResult" class="result-box"></div>
</div>
<!-- 用户验证/登录 (使用 PATCH 方法) -->
<div class="operation-section">
<h4>用户验证 (Check User Credentials)</h4>
<label for="verifyUsername">用户名:</label>
<input type="text" id="verifyUsername" placeholder="要验证的用户名">
<label for="verifyPasswordHash">密码哈希:</label>
<input type="password" id="verifyPasswordHash" placeholder="对应用户的密码哈希">
<button onclick="verifyUserCredentials()">验证用户</button>
<div id="verifyUserResult" class="result-box"></div>
</div>
<!-- 创建 User -->
<div class="operation-section">
<h4>创建用户</h4>
<label for="createUsername">用户名:</label>
<input type="text" id="createUsername" placeholder="新用户名">
<label for="createUserEmail">邮箱:</label>
<input type="email" id="createUserEmail" placeholder="user@example.com">
<label for="createUserPasswordHash">密码哈希 (例如: plainTextPassword的哈希值):</label>
<input type="password" id="createUserPasswordHash" placeholder="PasswordHash">
<button onclick="createUser()">创建 User</button>
<div id="createUserResult" class="result-box"></div>
</div>
<!-- 更新 User -->
<div class="operation-section">
<h4>更新用户</h4>
<label for="updateUserId">用户 ID:</label>
<input type="number" id="updateUserId" value="1">
<label for="updateUsername">新用户名:</label>
<input type="text" id="updateUsername" placeholder="更新后的用户名">
<label for="updateUserEmail">新邮箱:</label>
<input type="email" id="updateUserEmail" placeholder="updated@example.com">
<label for="updateUserPasswordHash">新密码哈希:</label>
<input type="password" id="updateUserPasswordHash" placeholder="UpdatedPasswordHash">
<button onclick="updateUser()">更新 User</button>
<div id="updateUserResult" class="result-box"></div>
</div>
<!-- 删除 User -->
<div class="operation-section">
<h4>删除用户</h4>
<label for="deleteUserId">用户 ID:</label>
<input type="number" id="deleteUserId" value="1">
<button onclick="deleteUser()">删除 User</button>
<div id="deleteUserResult" class="result-box"></div>
</div>
</div>
</div>
<script>
// === 配置您的 API 基础 URL ===
// 如果您的 API 运行在其他端口或地址,请修改此变量
const BASE_URL = 'http://localhost:5071';
// 对于 HTTPS可能需要改为 'https://localhost:5001'
// === 辅助函数 ===
async function fetchData(url, method = 'GET', data = null) {
const options = {
method: method,
headers: {
'Content-Type': 'application/json',
},
};
if (data) {
options.body = JSON.stringify(data);
}
try {
const response = await fetch(url, options);
let result;
// 尝试解析JSON响应但对于204 No Content等情况可能没有响应体
if (response.headers.get("content-type")?.includes("application/json")) {
result = await response.json();
} else {
result = await response.text(); // 如果不是 JSON尝试获取文本
}
if (!response.ok) {
throw new Error(`HTTP 错误! Status: ${response.status}, Message: ${result}`);
}
return result;
} catch (error) {
console.error('Fetch error:', error);
throw error;
}
}
function displayResult(elementId, data, isError = false) {
const resultBox = document.getElementById(elementId);
resultBox.innerHTML = '';
if (isError) {
resultBox.classList.add('error');
resultBox.textContent = `Error: ${data}`;
} else {
resultBox.classList.remove('error');
resultBox.classList.add('success');
if (typeof data === 'object') {
resultBox.textContent = JSON.stringify(data, null, 2);
} else {
resultBox.textContent = data;
}
}
resultBox.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
// === Todo Functions ===
async function getAllTodos() {
const resultBox = document.getElementById('allTodosResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '加载中...';
try {
const todos = await fetchData(`${BASE_URL}/todos`);
displayResult('allTodosResult', todos);
} catch (error) {
displayResult('allTodosResult', error.message, true);
}
}
async function getTodoById() {
const id = document.getElementById('getTodoId').value;
if (!id) {
displayResult('singleTodoResult', '请输入待办事项 ID。', true);
return;
}
const resultBox = document.getElementById('singleTodoResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '加载中...';
try {
const todo = await fetchData(`${BASE_URL}/todos/${id}`);
displayResult('singleTodoResult', todo);
} catch (error) {
displayResult('singleTodoResult', error.message, true);
}
}
async function createTodo() {
const title = document.getElementById('createTodoTitle').value;
const isCompleted = document.getElementById('createTodoIsCompleted').checked;
const userId = parseInt(document.getElementById('createTodoUserId').value);
if (!title) {
displayResult('createTodoResult', '标题不能为空。', true);
return;
}
if (isNaN(userId)) {
displayResult('createTodoResult', '用户ID必须是数字。', true);
return;
}
const newTodo = {
title: title,
isCompleted: isCompleted,
userId: userId
};
const resultBox = document.getElementById('createTodoResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '创建中...';
try {
const createdTodo = await fetchData(`${BASE_URL}/todos`, 'POST', newTodo);
displayResult('createTodoResult', createdTodo);
// 刷新所有 Todo 列表
getAllTodos();
} catch (error) {
displayResult('createTodoResult', error.message, true);
}
}
async function updateTodo() {
const id = document.getElementById('updateTodoId').value;
const title = document.getElementById('updateTodoTitle').value;
const isCompleted = document.getElementById('updateTodoIsCompleted').checked;
const userId = parseInt(document.getElementById('updateTodoUserId').value);
if (!id) {
displayResult('updateTodoResult', '请输入待办事项 ID。', true);
return;
}
if (!title) {
displayResult('updateTodoResult', '标题不能为空。', true);
return;
}
if (isNaN(userId)) {
displayResult('updateTodoResult', '用户ID必须是数字。', true);
return;
}
const updatedTodo = {
id: parseInt(id), // ID 也需要包含在 PUT 请求体中
title: title,
isCompleted: isCompleted,
userId: userId
};
const resultBox = document.getElementById('updateTodoResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '更新中...';
try {
await fetchData(`${BASE_URL}/todos/${id}`, 'PUT', updatedTodo);
displayResult('updateTodoResult', `待办事项 (ID: ${id}) 更新成功。`);
getTodoById(); // 刷新单个Todo
getAllTodos(); // 刷新所有Todo
} catch (error) {
displayResult('updateTodoResult', error.message, true);
}
}
async function deleteTodo() {
const id = document.getElementById('deleteTodoId').value;
if (!id) {
displayResult('deleteTodoResult', '请输入待办事项 ID。', true);
return;
}
const resultBox = document.getElementById('deleteTodoResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '删除中...';
try {
const response = await fetchData(`${BASE_URL}/todos/${id}`, 'DELETE');
displayResult('deleteTodoResult', response);
getAllTodos(); // 刷新所有Todo
} catch (error) {
displayResult('deleteTodoResult', error.message, true);
}
}
// === User Functions ===
async function getAllUsers() {
const resultBox = document.getElementById('allUsersResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '加载中...';
try {
const users = await fetchData(`${BASE_URL}/users`);
displayResult('allUsersResult', users);
} catch (error) {
displayResult('allUsersResult', error.message, true);
}
}
async function getUserById() {
const id = document.getElementById('getUserId').value;
if (!id) {
displayResult('singleUserResult', '请输入用户 ID。', true);
return;
}
const resultBox = document.getElementById('singleUserResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '加载中...';
try {
const user = await fetchData(`${BASE_URL}/users/${id}`);
displayResult('singleUserResult', user);
} catch (error) {
displayResult('singleUserResult', error.message, true);
}
}
async function createUser() {
const username = document.getElementById('createUsername').value;
const email = document.getElementById('createUserEmail').value;
const passwordHash = document.getElementById('createUserPasswordHash').value;
if (!username || !email || !passwordHash) {
displayResult('createUserResult', '用户名、邮箱和密码哈希不能为空。', true);
return;
}
const newUser = {
username: username,
email: email,
passwordHash: passwordHash
};
const resultBox = document.getElementById('createUserResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '创建中...';
try {
const createdUser = await fetchData(`${BASE_URL}/users`, 'POST', newUser);
displayResult('createUserResult', createdUser);
getAllUsers(); // 刷新所有用户列表
} catch (error) {
displayResult('createUserResult', error.message, true);
}
}
// PACTH /users - 验证用户凭据
async function verifyUserCredentials() {
const username = document.getElementById('verifyUsername').value;
const passwordHash = document.getElementById('verifyPasswordHash').value;
if (!username || !passwordHash) {
displayResult('verifyUserResult', '用户名和密码哈希不能为空。', true);
return;
}
const userToVerify = {
// PATCH 请求体中通常不包含 ID因为您的 API 是通过 Username 来查找
// 但如果需要,也可以写上 Id: 0 或其他占位符
username: username,
passwordHash: passwordHash
};
const resultBox = document.getElementById('verifyUserResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '验证中...';
try {
// 使用 PATCH 方法发送请求
const response = await fetchData(`${BASE_URL}/users`, 'PATCH', userToVerify);
displayResult('verifyUserResult', response);
} catch (error) {
// 如果 API 返回的是 BadRequest (400)fetchData 会抛出异常
// 异常的 message 应该包含 API 返回的错误信息
displayResult('verifyUserResult', error.message, true);
}
}
async function updateUser() {
const id = document.getElementById('updateUserId').value;
const username = document.getElementById('updateUsername').value;
const email = document.getElementById('updateUserEmail').value;
const passwordHash = document.getElementById('updateUserPasswordHash').value;
if (!id) {
displayResult('updateUserResult', '请输入用户 ID。', true);
return;
}
if (!username || !email || !passwordHash) {
displayResult('updateUserResult', '用户名、邮箱和密码哈希不能为空。', true);
return;
}
const updatedUser = {
id: parseInt(id), // ID 也需要包含在 PUT 请求体中
username: username,
email: email,
passwordHash: passwordHash
};
const resultBox = document.getElementById('updateUserResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '更新中...';
try {
await fetchData(`${BASE_URL}/users/${id}`, 'PUT', updatedUser);
displayResult('updateUserResult', `用户 (ID: ${id}) 更新成功。`);
getUserById(); // 刷新单个用户
getAllUsers(); // 刷新所有用户
} catch (error) {
displayResult('updateUserResult', error.message, true);
}
}
async function deleteUser() {
const id = document.getElementById('deleteUserId').value;
if (!id) {
displayResult('deleteUserResult', '请输入用户 ID。', true);
return;
}
const resultBox = document.getElementById('deleteUserResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '删除中...';
try {
const response = await fetchData(`${BASE_URL}/users/${id}`, 'DELETE');
displayResult('deleteUserResult', response);
getAllUsers(); // 刷新所有用户列表
} catch (error) {
displayResult('deleteUserResult', error.message, true);
}
}
// 页面加载完成后自动获取所有待办事项和用户
document.addEventListener('DOMContentLoaded', () => {
getAllTodos();
getAllUsers();
});
</script>
</body>
</html>