225 lines
7.1 KiB
HTML
225 lines
7.1 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>个人工具箱 - 汉字字帖生成器</title>
|
|
<style>
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
margin: 0;
|
|
padding: 0;
|
|
background-color: #f5f5f7;
|
|
color: #1d1d1f;
|
|
}
|
|
.container {
|
|
max-width: 1000px;
|
|
margin: 0 auto;
|
|
padding: 40px 20px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 24px;
|
|
}
|
|
header {
|
|
text-align: center;
|
|
margin-bottom: 10px;
|
|
}
|
|
header h1 { font-size: 32px; margin-bottom: 8px; }
|
|
header p { color: #86868b; margin: 0; }
|
|
|
|
.card {
|
|
background: white;
|
|
border-radius: 16px;
|
|
padding: 28px;
|
|
box-shadow: 0 8px 30px rgba(0,0,0,0.04);
|
|
}
|
|
|
|
.form-layout {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20px;
|
|
}
|
|
|
|
.input-row-top {
|
|
width: 100%;
|
|
}
|
|
|
|
.input-row-bottom {
|
|
display: flex;
|
|
gap: 16px;
|
|
align-items: flex-end;
|
|
}
|
|
|
|
.input-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
}
|
|
.input-group.flex-main { flex: 2; }
|
|
.input-group.flex-side { flex: 1; }
|
|
|
|
label {
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
color: #1d1d1f;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
input[type="text"] {
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
padding: 14px 16px;
|
|
border: 1px solid #d2d2d7;
|
|
border-radius: 10px;
|
|
font-size: 18px;
|
|
background-color: #fbfbfd;
|
|
transition: all 0.2s;
|
|
}
|
|
input[type="text"]:focus {
|
|
border-color: #0071e3;
|
|
background-color: #fff;
|
|
box-shadow: 0 0 0 4px rgba(0,113,227,0.1);
|
|
outline: none;
|
|
}
|
|
|
|
select {
|
|
appearance: none;
|
|
padding: 12px 16px;
|
|
border: 1px solid #d2d2d7;
|
|
border-radius: 10px;
|
|
font-size: 15px;
|
|
background-color: #fbfbfd;
|
|
cursor: pointer;
|
|
}
|
|
|
|
button {
|
|
background-color: #0071e3;
|
|
color: white;
|
|
border: none;
|
|
padding: 14px 32px;
|
|
border-radius: 10px;
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
height: 48px;
|
|
}
|
|
button:hover { background-color: #0077ed; transform: translateY(-1px); }
|
|
button:active { transform: translateY(0); }
|
|
|
|
#preview-container {
|
|
width: 100%;
|
|
height: 850px;
|
|
border-radius: 16px;
|
|
overflow: hidden;
|
|
background: #fff;
|
|
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
|
|
display: none;
|
|
}
|
|
iframe { width: 100%; height: 100%; border: none; }
|
|
|
|
.empty-state {
|
|
text-align: center;
|
|
padding: 80px 0;
|
|
border: 2px dashed #d2d2d7;
|
|
border-radius: 16px;
|
|
color: #86868b;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<header>
|
|
<h1>汉字字帖工具箱</h1>
|
|
<p>生成标准笔顺教学字帖,支持 A4/Letter 打印</p>
|
|
</header>
|
|
|
|
<div class="card">
|
|
<div class="form-layout">
|
|
<div class="input-row-top">
|
|
<div class="input-group">
|
|
<label for="chars">输入想要生成的汉字</label>
|
|
<input type="text" id="chars" placeholder="例如:永和九年,岁在癸丑..." value="永">
|
|
</div>
|
|
</div>
|
|
<div class="input-row-bottom">
|
|
<div class="input-group flex-main">
|
|
<label for="mode">布局模式</label>
|
|
<select id="mode">
|
|
<option value="teaching">2x3 教学方格 (带笔顺、箭头、序号)</option>
|
|
<option value="step">步进式分解 (逐笔展示过程)</option>
|
|
</select>
|
|
</div>
|
|
<div class="input-group flex-side">
|
|
<label for="paper_size">纸张大小</label>
|
|
<select id="paper_size">
|
|
<option value="A4">A4 (210x297mm)</option>
|
|
<option value="Letter">Letter (8.5x11in)</option>
|
|
</select>
|
|
</div>
|
|
<button onclick="generatePDF()">生成预览</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="preview-container">
|
|
<iframe id="pdf-frame"></iframe>
|
|
</div>
|
|
|
|
<div id="empty-state" class="empty-state">
|
|
<p>在上方输入汉字并点击按钮,即可生成高清矢量字帖预览</p>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
async function generatePDF() {
|
|
const chars = document.getElementById('chars').value;
|
|
const mode = document.getElementById('mode').value;
|
|
const paper_size = document.getElementById('paper_size').value;
|
|
|
|
if (!chars.trim()) {
|
|
alert('请输入汉字');
|
|
return;
|
|
}
|
|
|
|
const btn = document.querySelector('button');
|
|
const originalText = btn.innerText;
|
|
btn.innerText = '正在绘图中...';
|
|
btn.disabled = true;
|
|
|
|
try {
|
|
const response = await fetch('/api/jitie/generate', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
chars: chars,
|
|
mode: mode,
|
|
flip_y: true,
|
|
paper_size: paper_size
|
|
})
|
|
});
|
|
|
|
if (response.ok) {
|
|
const blob = await response.blob();
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
document.getElementById('empty-state').style.display = 'none';
|
|
const container = document.getElementById('preview-container');
|
|
container.style.display = 'block';
|
|
document.getElementById('pdf-frame').src = url;
|
|
} else {
|
|
const err = await response.json();
|
|
alert('生成失败: ' + (err.error || '未知错误'));
|
|
}
|
|
} catch (e) {
|
|
alert('网络请求失败,请检查后端服务是否运行');
|
|
} finally {
|
|
btn.innerText = originalText;
|
|
btn.disabled = false;
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|