前端:
-
日间模式背景色:
- 使用 Bulma 的
primary-light
背景色#e3f2fd
。
- 使用 Bulma 的
-
夜间模式背景色:
- 使用深色背景
#1d1d1d
和#2e2e2e
作为卡片和代码区域的背景色。
- 使用深色背景
-
结果显示:
pre
元素的背景色为白色,以适应日间和夜间模式的不同配色方案。
-
主题切换:
- 点击主题切换按钮时,背景色和文本颜色会根据主题进行相应调整。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>提交问题和答案</title>
<!-- 引入Bulma CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
<!-- 引入Font Awesome 图标库 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<style>
body {
padding: 20px;
transition: background-color 0.3s, color 0.3s;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.card {
margin-bottom: 20px;
}
.card-content {
padding: 20px;
}
pre {
background-color: #f5f5f5;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
white-space: pre-wrap; /* 保持格式 */
word-wrap: break-word; /* 自动换行 */
}
.dark-theme {
background-color: #1d1d1d; /* 背景色用于夜间模式 */
color: #f5f5f5;
}
.dark-theme .card {
background-color: #2e2e2e; /* 卡片背景色用于夜间模式 */
}
.dark-theme pre {
background-color: #333; /* 代码显示背景色用于夜间模式 */
color: #f5f5f5;
}
.light-theme {
background-color: #e3f2fd; /* Bulma's primary-light color for light theme */
color: #333;
}
.light-theme .card {
background-color: #fff;
}
.light-theme pre {
background-color: #fff;
color: #333;
}
.theme-toggle {
position: absolute;
top: 20px;
right: 20px;
cursor: pointer;
font-size: 1.5em;
}
</style>
</head>
<body id="app" class="light-theme">
<div class="container">
<h1 class="title has-text-centered">提交问题和答案</h1>
<!-- 主题切换按钮 -->
<i id="themeToggle" class="fas fa-moon theme-toggle"></i>
<!-- 动态组件 -->
<div id="componentContainer" class="card">
<div class="card-content" id="dynamicComponent">
<!-- 动态组件会被插入到这里 -->
</div>
</div>
<!-- 组件选择 -->
<div class="card">
<div class="card-content">
<div class="field">
<label class="label">选择组件:</label>
<div class="control">
<div class="select">
<select id="componentSelect">
<option value="input-form">输入框提交</option>
<option value="upload-form">文件上传提交</option>
</select>
</div>
</div>
</div>
</div>
</div>
<!-- 显示结果 -->
<div class="card">
<div class="card-content">
<h2 class="subtitle">结果</h2>
<pre id="result"></pre>
</div>
</div>
</div>
<script>
// 组件模板
const inputFormTemplate = `
<section>
<h2 class="subtitle">通过输入框提交</h2>
<form id="inputForm">
<div class="field">
<label class="label" for="jsonInput">输入JSON数据:</label>
<div class="control">
<textarea class="textarea" id="jsonInput" rows="10" placeholder="在此输入JSON数据"></textarea>
</div>
</div>
<div class="control">
<button class="button is-primary" type="submit">提交</button>
</div>
</form>
</section>
`;
const uploadFormTemplate = `
<section>
<h2 class="subtitle">通过上传文件提交</h2>
<form id="uploadForm">
<div class="field">
<label class="label" for="jsonFile">选择JSON文件:</label>
<div class="control">
<input class="input" type="file" id="jsonFile" accept="application/json">
</div>
</div>
<div class="control">
<button class="button is-primary" type="submit">提交</button>
</div>
</form>
</section>
`;
// 处理组件切换
document.getElementById('componentSelect').addEventListener('change', function() {
const selectedComponent = this.value;
const componentContainer = document.getElementById('dynamicComponent');
if (selectedComponent === 'input-form') {
componentContainer.innerHTML = inputFormTemplate;
document.getElementById('inputForm').addEventListener('submit', async function(event) {
event.preventDefault();
const jsonInput = document.getElementById('jsonInput').value;
try {
const response = await fetch('/update.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: jsonInput
});
const result = await response.json();
document.getElementById('result').innerText = JSON.stringify(result, null, 2);
} catch (error) {
document.getElementById('result').innerText = '提交失败: ' + error.message;
}
});
} else if (selectedComponent === 'upload-form') {
componentContainer.innerHTML = uploadFormTemplate;
document.getElementById('uploadForm').addEventListener('submit', async function(event) {
event.preventDefault();
const fileInput = document.getElementById('jsonFile');
if (fileInput.files.length === 0) {
document.getElementById('result').innerText = '请选择一个JSON文件';
return;
}
const file = fileInput.files[0];
const reader = new FileReader();
reader.onload = async function(event) {
try {
const jsonInput = event.target.result;
const response = await fetch('/update.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: jsonInput
});
const result = await response.json();
document.getElementById('result').innerText = JSON.stringify(result, null, 2);
} catch (error) {
document.getElementById('result').innerText = '提交失败: ' + error.message;
}
};
reader.readAsText(file);
});
}
});
// 处理主题切换
document.getElementById('themeToggle').addEventListener('click', function() {
const body = document.body;
const isDarkTheme = body.classList.contains('dark-theme');
if (isDarkTheme) {
body.classList.remove('dark-theme');
body.classList.add('light-theme');
this.classList.remove('fa-sun');
this.classList.add('fa-moon');
} else {
body.classList.remove('light-theme');
body.classList.add('dark-theme');
this.classList.remove('fa-moon');
this.classList.add('fa-sun');
}
});
// 初始化组件
document.getElementById('componentSelect').dispatchEvent(new Event('change'));
</script>
</body>
</html>
后端
后端PHP代码:
- 从POST请求中获取JSON数据。
- 验证JSON数据格式。
- 检查数据是否重复并插入新记录。
- 记录日志以便在发生错误时进行调试。
- 返回插入成功的数量、重复数量及重复的题目。
<?php
header('Content-Type: application/json');
// 设置时区
date_default_timezone_set('Asia/Shanghai');
// 定义日志文件路径
$logFile = 'error_log.txt';
// 日志记录函数
function logError($message) {
global $logFile;
$date = date('Y-m-d H:i:s');
file_put_contents($logFile, "[$date] $message" . PHP_EOL, FILE_APPEND);
}
// 获取并解析输入的JSON数据
$data = json_decode(file_get_contents('php://input'), true);
if (json_last_error() !== JSON_ERROR_NONE) {
$errorMessage = 'Invalid JSON data';
logError($errorMessage);
echo json_encode(['status' => 'error', 'message' => $errorMessage]);
exit;
}
// 验证数据格式
foreach ($data as $entry) {
if (!isset($entry['q']) || !isset($entry['a'])) {
$errorMessage = 'Invalid data format';
logError($errorMessage);
echo json_encode(['status' => 'error', 'message' => $errorMessage]);
exit;
}
}
// 数据库连接配置
$host = 'localhost';
$dbname = 'question';
$user = 'your_username';
$pass = 'your_password';
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 准备SQL插入语句,包含时间字段
$insertStmt = $pdo->prepare("INSERT INTO wk_question (question, answer, time) VALUES (:question, :answer, :time)");
// 准备SQL查询重复记录
$checkStmt = $pdo->prepare("SELECT COUNT(*) FROM wk_question WHERE question = :question AND answer = :answer");
// 获取当前时间
$current_time = date('Y-m-d H:i:s');
// 开始事务
$pdo->beginTransaction();
$insertedCount = 0;
$duplicateCount = 0;
$duplicateQuestions = [];
// 遍历数据并插入数据库
foreach ($data as $entry) {
// 检查是否存在重复
$checkStmt->execute([':question' => $entry['q'], ':answer' => $entry['a']]);
$count = $checkStmt->fetchColumn();
if ($count > 0) {
// 记录重复项
$duplicateCount++;
$duplicateQuestions[] = $entry['q'];
} else {
// 插入新记录
$insertStmt->execute([':question' => $entry['q'], ':answer' => $entry['a'], ':time' => $current_time]);
$insertedCount++;
}
}
// 提交事务
$pdo->commit();
echo json_encode([
'status' => 'success',
'message' => 'Data processed successfully',
'inserted_count' => $insertedCount,
'duplicate_count' => $duplicateCount,
'duplicate_questions' => $duplicateQuestions
]);
} catch (PDOException $e) {
// 回滚事务
$pdo->rollBack();
$errorMessage = 'Database error: ' . $e->getMessage();
logError($errorMessage);
echo json_encode(['status' => 'error', 'message' => $errorMessage]);
}
原文地址有完整内容: