Skip to content

Commit 65dedb1

Browse files
committed
updatee
1 parent 61baefc commit 65dedb1

5 files changed

Lines changed: 72 additions & 29 deletions

File tree

README.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
# 📐 MathPaper - 智能数学试卷排版系统
22

3-
(Almost everything by Gemini, except idea)
3+
(Almost ~~everything~~50% by Gemini, except idea)
4+
5+
【2026.3.7 重大更新】重构代码,增加语法,更加贴合上海高考的排版同时也支持一定程度的风格个性化。
6+
7+
排版工作浩瀚复杂,不少功能实现难度大,如同不断贴补丁;目前版本做到与高考风格相似度 90% 左右,但受限于时间精力,不与高考完全一致,且可能带有一些本项目作者的排版习惯倾向而未向“完全复刻”妥协。
8+
9+
## 👀 排版效果预览
10+
![](preview.png)
411

512
![](screenshot.png)
613

@@ -10,18 +17,19 @@ MathPaper 是一个高效、所见即所得 (WYSIWYG) 的单文件 Web 排版工
1017

1118
## ✨ 核心特性
1219

13-
* **⚡ 稳定高效的 KaTeX 渲染 (v4.0)** 采用 Vue 组件隔离技术,完美解决了 KaTeX 直接操作 DOM 与 Vue 虚拟 DOM 之间的冲突,确保系统在复杂输入和频繁操作下仍保持稳定。左侧编辑后,右侧公式实时更新。
20+
* **⚡ 稳定高效的 KaTeX 渲染:** 采用 Vue 组件隔离技术,完美解决了 KaTeX 直接操作 DOM 与 Vue 虚拟 DOM 之间的冲突,确保系统在复杂输入和频繁操作下仍保持稳定。左侧编辑后,右侧公式实时更新。
1421
* **📃 智能分页与布局:** 实时监测内容高度,自动进行 A4 纸张分页。
1522
* **拖拽调整:** 拖动题目底部的蓝色手柄,精确控制题目下方留白。
1623
* **强制分页:** **双击**任何题目块,可在该题目之前插入强制分页符。
17-
* **🖋️ 智能输入解析 (v4.0)** 简化您的输入,系统自动识别并转换标签:
24+
* **🖋️ 智能输入解析:** 简化您的输入,系统自动识别并转换标签:
1825
* `# 试卷标题`:自动识别为试卷标题。
1926
* `## 方块记号`:转化为带边框的小标题。
2027
* `### 小标题`:转化为黑体的小标题,一般用于大题前的文字说明。
2128
* `1. 题目内容`:自动识别为大题号。
2229
* `(1) 小题内容``(1)小题内容`:自动识别为大题号下的小题号。
30+
* 在 20260307 更新后,添加了更多支持的语法。
2331
* **🖨️ 完美打印输出:** 专为打印和 PDF 导出优化。
24-
* **🎨 风格完美复刻:** 通过对 KaTeX 进行神奇 CSS 微操,复刻接近上海高考风格的排版(华文中宋 + Times New Roman)
32+
* **🎨 风格完美复刻:** 通过对 KaTeX 进行神奇 CSS 微操,复刻接近上海高考风格的排版
2533

2634
## 🛠️ 技术栈
2735

@@ -34,8 +42,4 @@ MathPaper 是一个高效、所见即所得 (WYSIWYG) 的单文件 Web 排版工
3442
1. **准备文件:** 项目下的 `index.html`
3543
2. **打开浏览器:** 在 Chrome 或 Edge 中直接打开此 HTML 文件。
3644
3. **开始编辑:** 在左侧输入框中粘贴您的试卷内容。
37-
4. **调整与导出:** 在右侧预览区进行拖拽和双击微调,满意后点击 **"打印 / 导出 PDF"** 按钮即可获得成品。
38-
39-
## 👀 排版预览
40-
41-
![](preview.png)
45+
4. **调整与导出:** 在右侧预览区进行拖拽和双击微调,满意后点击 **"打印 / 导出 PDF"** 按钮即可获得成品。

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<div id="app" class="h-screen flex flex-col">
2020
<header id="app-header" class="h-14 bg-white border-b flex items-center justify-between px-6 shrink-0 z-50">
2121
<div class="font-bold text-gray-700">
22-
<i class="fa-solid fa-check-double text-blue-600 mr-2"></i>MathPaper v1.0
22+
<i class="fa-solid fa-check-double text-blue-600 mr-2"></i>MathPaper v1.5
2323
</div>
2424
<div class="text-sm" :class="statusColor">
2525
<i class="fa-solid fa-circle text-[10px] mr-1"></i> {{ statusText }}

preview.png

220 KB
Loading

script.js

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -65,24 +65,26 @@ createApp({
6565
components: { MathBlock },
6666
setup() {
6767
// 初始示例
68-
const defaultText = `#0a 2050 年上海市普通高校冬季招生统一文化考试
68+
const defaultText = `#font simsun
69+
#size 15px
70+
71+
#0a 2050 年上海市普通高校冬季招生统一文化考试
6972
#0b 数学试卷
7073
#note (考试时间 120 分钟,满分 150 分)
7174
#note (试卷共 4 页,答题纸共 2 页)
7275
### 一、填空题(本大题共 12 题,第 1—6 题每题 4 分,第 7—12 题每题 5 分,共 54 分)
73-
1. 欧拉公式的提出者是_________.
74-
2. 上海高中数学共有选择性必修_________册.
75-
11. 已知抛物线 $\\Gamma: y^2=2px(p>0)$,对 $\\Gamma$ 上的任意一点 $P$,在 $\\Gamma$ 上均存在两点 $A,B$(与 $P$ 不重合),使得 $\\triangle ABP$ 为等边三角形,则 $\\Gamma$ 离心率的取值范围为________。
76-
12. 已知 $\\vec{a}, \\vec{b}, \\vec{c}$ 为平面内的单位向量,若对任意 $\\vec{a}, \\vec{b}$,均存在 $\\vec{c}$ 使 $\\vec{a} \\cdot \\vec{c}$ 与 $\\vec{b} \\cdot \\vec{c}$ 均小于 $\\dfrac 1 2$,则 $| \\vec{a} | + | \\vec{b} |$ 的最小值为________。
77-
76+
1. 欧拉公式的提出者是___。
77+
2. 上海高中数学共有选择性必修___册。(精确到 0.01)
78+
11. 已知抛物线 $\\Gamma: y^2=2px(p>0)$,对 $\\Gamma$ 上的任意一点 $P$,在 $\\Gamma$ 上均存在两点 $A,B$ (与 $P$ 不重合),使得 $\\triangle ABP$ 为等边三角形,则 $\\Gamma$ 离心率的取值范围为___。
79+
12. 已知 $\\vec{a}, \\vec{b}, \\vec{c}$ 为平面内的单位向量,若对任意 $\\vec{a}, \\vec{b}$,均存在 $\\vec{c}$ 使 $\\vec{a} \\cdot \\vec{c}$ 与 $\\vec{b} \\cdot \\vec{c}$ 均小于 $\\dfrac 1 2$,则 $| \\vec{a} | + | \\vec{b} |$ 的最小值为___。
7880
7981
### 二、选择题(本大题共 4 题,第 13、14 题每题 4 分,第 15、16 题每题 5 分,共 18 分)
80-
13. 下列关于等式 “$1+1=2$” 的说法正确的是_______.(不定项
82+
13. 下列关于等式 “$1+1=2$” 的说法正确的是___。(不定项)
8183
A. 既是真命题也是数学公理;
8284
B. 体现了数学公式的对称美;
8385
C. 体现了数学公式的简洁性;
8486
D. 运用了“等量代换”的思想。
85-
16. 给出以下两个命题,下列说法正确的是_______.
87+
16. 给出以下两个命题,下列说法正确的是___。
8688
(1)$\\left(\\sin \\dfrac \\pi 2\\right)'= \\cos \\dfrac \\pi 2$;
8789
(2)$\\left(\\cos \\dfrac \\pi 2\\right)'= \\sin \\dfrac \\pi 2$。
8890
A. (1) 为真命题, (2) 为真命题;
@@ -92,7 +94,7 @@ D. (1) 为假命题, (2) 为假命题。
9294
9395
### 三、解答题(本大题共 5 题,第 17—19 题每题 14 分,第 20—21 题每题 18 分,共 78 分)
9496
95-
21. 第 1 小题满分 4 分,第 2 小题满分 6 分,第 3 小题满分 8 分
97+
21. (第 1 小题满分 4 分,第 2 小题满分 6 分,第 3 小题满分 8 分)
9698
若函数 $f(x)$ 的定义域为 $D_f$,当对 $\\forall x \\in D_f$ 均有 $f(x)=f_0(x)$ 时,我们称 $f(x)$ 为 $f_0(x)$-函数。
9799
(1)判断 $f(x)=\\sin x$ 是否为 $\\sin x$-函数,并说明理由;
98100
(2)已知 $a \\in \\mathbb{R}$,$f(x)=a\\sqrt{1-x}$,当 $f(x)$ 为 $\\pi\\sqrt{1-x}$-函数时,求 $a$ 的值,并判断此时 $a$ 是否是有理数;
@@ -114,6 +116,12 @@ D. (1) 为假命题, (2) 为假命题。
114116
'### ': { type: 'title3', render: (content) => `<div class="third-title">${content}</div>` },
115117
};
116118

119+
const FONT_CONFIG = {
120+
'simsun': { family: 'simsun', offset: '-0.03em', scale: '1.05em' },
121+
'zhongsong': { family: '"STZhongsong", serif', offset: '0.045em', scale: '1em' },
122+
'shusong': { family: '"STShusong-Z01S", serif', offset: '0.045em', scale: '1em' },
123+
}
124+
117125
// --- 解析器 (包含新 Feature) ---
118126
const parse = () => {
119127
statusText.value = "解析中...";
@@ -124,16 +132,19 @@ D. (1) 为假命题, (2) 为假命题。
124132
let current = null;
125133
let idSeq = 1;
126134
let optionBuffer = []; // 选择题缓冲区
135+
let currentFont = 'zhongsong'; // 字体缓冲区
136+
let currentSize = '16px';
127137

128138
const fixFont = (str) => str.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
129139

130140
// [新增] 专门用于将缓存的选择题推入块中
131141
const flushOptions = () => {
132142
if (optionBuffer.length > 0) {
133143
// 启发式测算:剥除KaTeX标识符后计算最大字符长度
134-
let maxLen = Math.max(...optionBuffer.map(o => o.text.length));
144+
const getVisualLength = s => s.replace(/\$.*?\$/g, "###").replace(/<[^>]+>/g, "").split('').reduce((l, c) => l + (c.charCodeAt(0) > 255 ? 2 : 1), 0);
145+
let maxLen = Math.max(...optionBuffer.map(o => getVisualLength(o.text)));
135146
console.log(optionBuffer, "选项最大长度:", maxLen);
136-
let colsClass = maxLen <= 8 ? 'mcq-cols-4' : (maxLen <= 19 ? 'mcq-cols-2' : 'mcq-cols-1');
147+
let colsClass = maxLen <= 18 ? 'mcq-cols-4' : (maxLen <= 30 ? 'mcq-cols-2' : 'mcq-cols-1');
137148

138149
let optionsHtml = `<div class="mcq-options ${colsClass}">`;
139150
optionBuffer.forEach(opt => {
@@ -157,7 +168,6 @@ D. (1) 为假命题, (2) 为假命题。
157168
const content = fixFont(current.rawContent);
158169
const config = Object.values(FORMAT_CONFIG).find(c => c.type === current.type);
159170
if (config) { // 匹配到特殊格式
160-
console.log("渲染格式:", current.type, content);
161171
current.html = config.render(content);
162172
} else if (current.type === 'question') { // 题目
163173
current.html = `<ol start="${current.number}"><li>${content}</li></ol>`;
@@ -168,10 +178,22 @@ D. (1) 为假命题, (2) 为假命题。
168178
};
169179

170180
lines.forEach(line => {
171-
const trim0 = line.trim();
181+
const trim0 = line.trim().replace('___', '_________').replace('(_)', '($\\hspace{0.8cm}$)');
172182
// 处理中文字体包裹
173183
const trim = trim0.replace(/([\u4e00-\u9fff]+)/g, '<span class="chinese-fix">$1</span>');
174184

185+
// -1. 解析 meta 信息(字体大小等)
186+
// 匹配字体设置
187+
if (trim0.startsWith('#font ')) {
188+
currentFont = trim0.substring(6).trim();
189+
return;
190+
}
191+
// 匹配大小设置
192+
if (trim0.startsWith('#size ')) {
193+
currentSize = trim0.substring(6).trim();
194+
return;
195+
}
196+
175197
// 0. 判断是否为选择题选项 (兼容 A. A。A、A.)
176198
const mcqMatch = trim0.match(/^([A-D])[.]\s*(.*)/);
177199
if (mcqMatch) {
@@ -250,6 +272,15 @@ D. (1) 为假命题, (2) 为假命题。
250272
});
251273
}
252274

275+
console.log(currentFont, currentSize);
276+
if (FONT_CONFIG[currentFont]) {
277+
const cfg = FONT_CONFIG[currentFont];
278+
document.documentElement.style.setProperty('--paper-font-family', cfg.family);
279+
document.documentElement.style.setProperty('--paper-font-vertical-align', cfg.offset);
280+
document.documentElement.style.setProperty('--paper-font-scale-size', cfg.scale);
281+
}
282+
document.documentElement.style.setProperty('--paper-base-size', currentSize);
283+
253284
allBlocks.value = blocks;
254285
nextTick(layout);
255286
};

style.css

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,23 @@
66
--paper-font-scale-size: 1em; /* 字号系数,万一某个字体的字特别大/小之类 */
77
}
88

9+
@font-face {
10+
font-family: 'bracket-fix';
11+
src: local('simsun');
12+
unicode-range: U+0028, U+0029;
13+
}
14+
915
/* =========================================
1016
1. 您的原始样式 (Scope 隔离版 - 未修改)
1117
========================================= */
1218
.paper-style-scope {
13-
font-family: Times New Roman, var(--paper-font-family);
19+
font-family: 'bracket-fix', Times New Roman, var(--paper-font-family);
1420
color: #000000;
1521
line-height: 1.8em;
1622
word-break: break-all;
17-
font-size: 16px;
23+
font-size: var(--paper-base-size);
24+
line-break: strict;
25+
hanging-punctuation: last allow-end;
1826
}
1927

2028
.paper-style-scope .chinese-fix {
@@ -36,15 +44,15 @@
3644
content: "(" counter(pp-counter) ")";
3745
counter-increment: pp-counter;
3846
position: absolute;
39-
left: -25px;
47+
left: -30px;
4048
color: black;
4149
font-size: 1.1em;
42-
font-family: "Times New Roman";
50+
font-family: 'bracket-fix', Times New Roman, var(--paper-font-family);
4351
}
4452

4553
.paper-style-scope li { counter-reset: pp-counter; }
4654
.paper-style-scope li::marker { font-size: 1.1em; margin-right: 10px; font-family: "Times New Roman"; }
47-
.paper-style-scope pp { margin-left: 25px; position: relative; display: block; }
55+
.paper-style-scope pp { margin-left: 30px; position: relative; display: block; }
4856
.paper-style-scope ol { list-style: decimal; padding-left: 2em; margin: 0; }
4957
.paper-style-scope ul { list-style: disc; padding-left: 2em; margin: 0; }
5058
.paper-style-scope strong { font-weight: bold; }
@@ -102,7 +110,7 @@
102110
display: flex;
103111
justify-content: center;
104112
align-items: center;
105-
font-family: "Times New Roman", "Kaiti SC", "STKaiti", serif;
113+
font-family: "Times New Roman", "STKaiti", "Kaiti SC", serif;
106114
font-size: 0.9em;
107115
/* color: #666; 备注通常颜色稍浅 */
108116
text-align: center;

0 commit comments

Comments
 (0)