main.html 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. <!DOCTYPE html>
  2. <html lang="zh">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Summernote富文本编辑器</title>
  7. <th:block th:include="include :: header('Summernote富文本编辑器')" />
  8. <th:block th:include="include :: summernote-css" />
  9. <style>
  10. .result-panel {
  11. border-left: 1px solid #e7eaec;
  12. height: 100%;
  13. padding: 15px;
  14. background-color: #f9f9f9;
  15. }
  16. .error-item {
  17. margin-bottom: 20px;
  18. padding: 15px;
  19. border-radius: 5px;
  20. background-color: #fff;
  21. box-shadow: 0 2px 5px rgba(0,0,0,0.1);
  22. }
  23. .error-title {
  24. font-weight: bold;
  25. margin-bottom: 12px;
  26. font-size: 16px;
  27. color: #ed5565;
  28. }
  29. .common-error .error-title {
  30. color: #ed5565;
  31. }
  32. .political-error .error-title {
  33. color: #ed5565;
  34. }
  35. .suggestion-table {
  36. width: 100%;
  37. margin-bottom: 10px;
  38. border-collapse: collapse;
  39. word-break: break-all;
  40. word-wrap: break-word;
  41. white-space: normal;
  42. }
  43. .suggestion-table th, .suggestion-table td {
  44. padding: 8px;
  45. border: 1px solid #ddd;
  46. text-align: left;
  47. }
  48. .suggestion-table th {
  49. width: 80px;
  50. background-color: #f9f9f9;
  51. }
  52. .confidence {
  53. font-size: 12px;
  54. color: #888;
  55. margin-top: 5px;
  56. }
  57. .political-warning {
  58. font-weight: bold;
  59. }
  60. .error-highlight {
  61. background-color: #ffcccc !important;
  62. color: #ed5565 !important;
  63. border-bottom: 1px dashed #ed5565 !important;
  64. padding: 0 2px !important;
  65. }
  66. .error-content a {
  67. display: inline-block;
  68. max-width: 200px;
  69. overflow: hidden;
  70. text-overflow: ellipsis;
  71. white-space: nowrap;
  72. vertical-align: bottom;
  73. }
  74. /* 编辑器容器固定高度 */
  75. .ibox-content.no-padding {
  76. height: 650px;
  77. display: flex;
  78. flex-direction: column;
  79. position: relative;
  80. }
  81. /* 编辑器区域自动滚动 */
  82. .summernote {
  83. flex: 1;
  84. display: flex;
  85. flex-direction: column;
  86. }
  87. /* Summernote编辑器包装器 */
  88. .note-editor {
  89. flex: 1;
  90. display: flex;
  91. flex-direction: column;
  92. overflow: hidden;
  93. }
  94. /* Summernote编辑区域 */
  95. .note-editable {
  96. flex: 1;
  97. overflow-y: auto !important;
  98. min-height: 200px;
  99. }
  100. /* 底部按钮固定在容器底部 */
  101. .editor-footer {
  102. position: sticky;
  103. bottom: 0;
  104. background-color: #fff;
  105. z-index: 100;
  106. padding: 15px;
  107. border-top: 1px solid #e7eaec;
  108. text-align: center;
  109. }
  110. /* 校对结果面板样式 - 电脑版 */
  111. .col-sm-4 {
  112. position: fixed !important;
  113. right: 0px !important;
  114. z-index: 1000 !important;
  115. max-height: 80vh !important;
  116. }
  117. .col-sm-4 .ibox-content {
  118. max-height: calc(96vh - 50px) !important;
  119. overflow-y: auto !important;
  120. }
  121. /* 新增误报按钮样式 */
  122. .false-positive-btn {
  123. font-size: 12px;
  124. background-color: #f8f9fa;
  125. border: 1px solid #ddd;
  126. border-radius: 3px;
  127. color: #6c757d;
  128. cursor: pointer;
  129. transition: all 0.2s;
  130. display: block;
  131. text-align: center;
  132. padding: 4px 8px;
  133. margin-top: 8px;
  134. }
  135. .false-positive-btn:hover {
  136. background-color: #e9ecef;
  137. color: #495057;
  138. }
  139. .false-positive-btn.reported {
  140. color: #155724;
  141. border-color: #c3e6cb;
  142. cursor: default;
  143. }
  144. .false-positive-btn i {
  145. margin-right: 4px;
  146. }
  147. .error-actions {
  148. margin-bottom: 10px;
  149. text-align: right;
  150. }
  151. .error-type-divider {
  152. margin: 15px 0;
  153. border-top: 1px dashed #e7eaec;
  154. }
  155. /* 加载状态样式 */
  156. .loading-overlay {
  157. position: absolute;
  158. top: 0;
  159. left: 0;
  160. right: 0;
  161. bottom: 0;
  162. background: rgba(255, 255, 255, 0.8);
  163. display: flex;
  164. align-items: center;
  165. justify-content: center;
  166. z-index: 1000;
  167. }
  168. /* ========== 手机版适配样式 ========== */
  169. @media (max-width: 768px) {
  170. /* 整体布局调整 */
  171. .wrapper-content {
  172. padding: 10px;
  173. }
  174. .row {
  175. display: block;
  176. margin: 0;
  177. }
  178. /* 编辑器区域 - 全宽度 */
  179. .col-sm-8 {
  180. width: 100%;
  181. padding: 0;
  182. margin-bottom: 0;
  183. }
  184. /* 结果面板 - 手机版改为正常文档流,在编辑器下方 */
  185. .col-sm-4 {
  186. position: static !important;
  187. width: 100% !important;
  188. max-height: none !important;
  189. margin-top: 20px;
  190. }
  191. .col-sm-4 .ibox-content {
  192. max-height: none !important;
  193. height: auto;
  194. min-height: 300px;
  195. max-height: 500px;
  196. overflow-y: auto;
  197. }
  198. /* 编辑器高度调整 */
  199. .ibox-content.no-padding {
  200. height: 500px;
  201. }
  202. /* 按钮调整 */
  203. .editor-footer .btn {
  204. padding: 10px 15px;
  205. font-size: 14px;
  206. margin: 0 5px;
  207. }
  208. /* 表格字体调整 */
  209. .suggestion-table {
  210. font-size: 14px;
  211. }
  212. .suggestion-table th,
  213. .suggestion-table td {
  214. padding: 10px 8px;
  215. }
  216. /* 错误项间距调整 */
  217. .error-item {
  218. padding: 12px;
  219. margin-bottom: 15px;
  220. }
  221. .error-title {
  222. font-size: 16px;
  223. }
  224. /* Summernote 工具栏优化 */
  225. .note-toolbar {
  226. padding: 8px !important;
  227. }
  228. .note-toolbar .btn-group {
  229. margin-bottom: 5px;
  230. }
  231. .note-toolbar .btn {
  232. padding: 8px 10px;
  233. font-size: 13px;
  234. }
  235. .note-editable {
  236. font-size: 16px; /* 手机端字体放大 */
  237. }
  238. /* 手机版底部间距 */
  239. .wrapper {
  240. padding-bottom: 20px;
  241. }
  242. }
  243. /* 超小屏幕设备 */
  244. @media (max-width: 480px) {
  245. .ibox-content.no-padding {
  246. height: 400px;
  247. }
  248. .editor-footer .btn {
  249. padding: 8px 12px;
  250. font-size: 13px;
  251. margin: 0 3px;
  252. }
  253. .suggestion-table {
  254. font-size: 13px;
  255. }
  256. .error-content h4 {
  257. font-size: 15px;
  258. }
  259. .col-sm-4 .ibox-content {
  260. min-height: 250px;
  261. max-height: 400px;
  262. }
  263. }
  264. </style>
  265. </head>
  266. <body class="gray-bg">
  267. <div class="wrapper wrapper-content">
  268. <div class="row">
  269. <!-- 编辑器区域 -->
  270. <div class="col-sm-8">
  271. <div class="ibox float-e-margins">
  272. <div class="ibox-content no-padding" style="position: relative;">
  273. <!-- 加载遮罩层 -->
  274. <div id="loadingOverlay" class="loading-overlay" style="display: none;">
  275. <div style="text-align: center;">
  276. <i class="fa fa-spinner fa-spin fa-3x fa-fw" style="color: #1ab394;"></i>
  277. <p style="margin-top: 15px; font-size: 16px;">校对中,请稍候...</p>
  278. </div>
  279. </div>
  280. <div class="summernote"></div>
  281. <div class="editor-footer">
  282. <button id="checkBtn" class="btn btn-primary btn-sm">
  283. <i class="fa fa-check"></i> 校对
  284. </button>
  285. <button id="resetBtn" class="btn btn-warning btn-sm">
  286. <i class="fa fa-refresh"></i> 重置
  287. </button>
  288. <button id="clearBtn" class="btn btn-danger btn-sm">
  289. <i class="fa fa-trash"></i> 清空
  290. </button>
  291. </div>
  292. </div>
  293. </div>
  294. </div>
  295. <!-- 结果面板区域 -->
  296. <div class="col-sm-4" id="resultsPanel">
  297. <!-- 新增:独立的安全警告模块 -->
  298. <div class="security-alert-panel" style="
  299. background: linear-gradient(135deg, #fff5f5, #ffe6e6);
  300. border: 2px solid #ff4d4f;
  301. border-radius: 8px;
  302. margin-bottom: 15px;
  303. padding: 15px;
  304. box-shadow: 0 3px 10px rgba(255, 77, 79, 0.2);
  305. ">
  306. <div style="
  307. display: flex;
  308. align-items: center;
  309. justify-content: center;
  310. gap: 10px;
  311. ">
  312. <i class="fa fa-exclamation-triangle" style="
  313. color: #ff4d4f;
  314. font-size: 20px;
  315. flex-shrink: 0;
  316. "></i>
  317. <div style="
  318. color: #ff4d4f;
  319. font-weight: bold;
  320. font-size: 15px;
  321. text-align: center;
  322. line-height: 1.4;
  323. ">
  324. 严禁处理涉密信息<br>
  325. <span style="
  326. font-size: 12px;
  327. font-weight: normal;
  328. color: #d9363e;
  329. margin-top: 3px;
  330. display: block;
  331. ">
  332. </span>
  333. </div>
  334. </div>
  335. </div>
  336. <div class="ibox float-e-margins fixed-result-panel">
  337. <div class="ibox-title">
  338. <h5>校对结果</h5>
  339. </div>
  340. <div class="ibox-content result-panel">
  341. <div id="checkResults">
  342. <div class="text-muted" style="text-align: center; padding: 20px;">
  343. <i class="fa fa-info-circle fa-2x"></i>
  344. <p>点击"校对"按钮检查文档内容</p>
  345. </div>
  346. </div>
  347. </div>
  348. </div>
  349. </div>
  350. </div>
  351. </div>
  352. <th:block th:include="include :: footer" />
  353. <th:block th:include="include :: summernote-js" />
  354. <script>
  355. var initialContent = '';
  356. var prefix = ctx + "project/jiaodui";
  357. var wordResults = ctx + "project/wordresults";
  358. var currentErrors = [];
  359. var falsePositiveErrors = [];
  360. $(document).ready(function () {
  361. // Summernote 初始化
  362. $('.summernote').summernote({
  363. lang: 'zh-CN',
  364. height: 460,
  365. toolbar: [
  366. ['style', ['bold', 'italic', 'underline', 'clear']],
  367. ['font', ['strikethrough', 'superscript', 'subscript']],
  368. ['fontsize', ['fontsize']],
  369. ['color', ['color']],
  370. ['para', ['ul', 'ol', 'paragraph']],
  371. ['height', ['height']],
  372. ['insert', ['picture', 'link', 'video', 'table', 'hr']],
  373. ['view', ['fullscreen', 'codeview', 'help']]
  374. ]
  375. });
  376. // 显示加载状态
  377. function showLoading() {
  378. $('#loadingOverlay').show();
  379. $('#checkBtn').prop('disabled', true);
  380. }
  381. // 隐藏加载状态
  382. function hideLoading() {
  383. $('#loadingOverlay').hide();
  384. $('#checkBtn').prop('disabled', false);
  385. }
  386. // 清除所有错误高亮
  387. function clearErrorHighlights() {
  388. var content = $('.summernote').summernote('code');
  389. content = content.replace(/<span class="error-highlight"[^>]*>(.*?)<\/span>/gi, '$1');
  390. $('.summernote').summernote('code', content);
  391. }
  392. // 高亮显示错误词 - 完整版
  393. function highlightErrors(errors) {
  394. var content = $('.summernote').summernote('code');
  395. // 先清除旧的高亮
  396. content = clearErrorHighlightsFromContent(content);
  397. // 分离有位置信息和无位置信息的错误
  398. var errorsWithPosition = [];
  399. var errorsWithoutPosition = [];
  400. errors.forEach(function(error) {
  401. if (falsePositiveErrors.includes(error.id)) {
  402. return;
  403. }
  404. // 检查是否有有效的起止位置信息
  405. if (isValidPosition(error)) {
  406. errorsWithPosition.push(error);
  407. } else {
  408. errorsWithoutPosition.push(error);
  409. }
  410. });
  411. console.log('有位置信息的错误:', errorsWithPosition.length);
  412. console.log('无位置信息的错误:', errorsWithoutPosition.length);
  413. // 先处理有位置信息的错误(从后往前)
  414. if (errorsWithPosition.length > 0) {
  415. content = highlightErrorsWithPosition(content, errorsWithPosition);
  416. }
  417. // 再处理无位置信息的错误
  418. if (errorsWithoutPosition.length > 0) {
  419. content = highlightErrorsWithoutPosition(content, errorsWithoutPosition);
  420. }
  421. $('.summernote').summernote('code', content);
  422. }
  423. // 检查位置信息是否有效
  424. function isValidPosition(error) {
  425. return error.startpos !== undefined &&
  426. error.endpos !== undefined &&
  427. error.startpos >= 0 &&
  428. error.endpos > error.startpos &&
  429. error.wrongWord;
  430. }
  431. // 从内容中清除高亮(不更新编辑器)
  432. function clearErrorHighlightsFromContent(content) {
  433. return content.replace(/<span class="error-highlight"[^>]*>(.*?)<\/span>/gi, '$1');
  434. }
  435. // 高亮有位置信息的错误
  436. function highlightErrorsWithPosition(htmlContent, errors) {
  437. var plainText = getPlainText(htmlContent);
  438. console.log('纯文本长度:', plainText.length);
  439. console.log('纯文本内容:', plainText);
  440. // 按位置从后往前高亮,避免位置偏移
  441. errors.sort((a, b) => b.startpos - a.startpos).forEach(function(error, index) {
  442. console.log(`处理错误 ${index + 1}:`, error);
  443. try {
  444. var newContent = highlightSingleErrorWithPosition(htmlContent, plainText, error);
  445. if (newContent) {
  446. htmlContent = newContent;
  447. } else {
  448. // 位置高亮失败,回退到全局替换
  449. console.warn('位置高亮失败,使用全局替换:', error.wrongWord);
  450. htmlContent = highlightWithGlobalReplace(htmlContent, error);
  451. }
  452. } catch (e) {
  453. console.error('位置高亮异常,使用全局替换:', error.wrongWord, e);
  454. htmlContent = highlightWithGlobalReplace(htmlContent, error);
  455. }
  456. });
  457. return htmlContent;
  458. }
  459. // 高亮单个有位置信息的错误
  460. function highlightSingleErrorWithPosition(htmlContent, plainText, error) {
  461. var errorText = plainText.substring(error.startpos, error.endpos);
  462. console.log('期望的错误文本:', error.wrongWord);
  463. console.log('实际提取的文本:', errorText);
  464. console.log('位置范围:', error.startpos, '-', error.endpos);
  465. // 验证提取的文本是否匹配
  466. if (errorText !== error.wrongWord) {
  467. console.warn('位置信息不准确,期望:', error.wrongWord, '实际:', errorText);
  468. return null;
  469. }
  470. // 使用DOM方式精确定位
  471. var tempDiv = document.createElement('div');
  472. tempDiv.innerHTML = htmlContent;
  473. var result = findAndHighlightTextNode(tempDiv, error, plainText);
  474. if (result.found) {
  475. return tempDiv.innerHTML;
  476. } else {
  477. return null;
  478. }
  479. }
  480. // 查找并高亮文本节点
  481. function findAndHighlightTextNode(element, error, plainText) {
  482. var walker = document.createTreeWalker(
  483. element,
  484. NodeFilter.SHOW_TEXT,
  485. null,
  486. false
  487. );
  488. var currentGlobalPos = 0;
  489. var node = walker.nextNode();
  490. while (node) {
  491. var nodeText = node.textContent;
  492. var nodeLength = nodeText.length;
  493. // 检查错误是否在这个文本节点中
  494. if (error.startpos >= currentGlobalPos && error.endpos <= currentGlobalPos + nodeLength) {
  495. var nodeStart = error.startpos - currentGlobalPos;
  496. var nodeEnd = error.endpos - currentGlobalPos;
  497. // 验证节点内的文本是否匹配
  498. var nodeErrorText = nodeText.substring(nodeStart, nodeEnd);
  499. if (nodeErrorText === error.wrongWord) {
  500. // 创建高亮span
  501. var span = document.createElement('span');
  502. span.className = 'error-highlight';
  503. span.setAttribute('data-error-id', error.id);
  504. span.textContent = nodeErrorText;
  505. // 替换文本节点
  506. var beforeText = nodeText.substring(0, nodeStart);
  507. var afterText = nodeText.substring(nodeEnd);
  508. var parent = node.parentNode;
  509. if (beforeText) {
  510. parent.insertBefore(document.createTextNode(beforeText), node);
  511. }
  512. parent.insertBefore(span, node);
  513. if (afterText) {
  514. parent.insertBefore(document.createTextNode(afterText), node);
  515. }
  516. parent.removeChild(node);
  517. return { found: true };
  518. }
  519. }
  520. currentGlobalPos += nodeLength;
  521. node = walker.nextNode();
  522. }
  523. return { found: false };
  524. }
  525. // 高亮无位置信息的错误(全局替换)
  526. function highlightErrorsWithoutPosition(content, errors) {
  527. errors.forEach(function(error) {
  528. content = highlightWithGlobalReplace(content, error);
  529. });
  530. return content;
  531. }
  532. // 全局文本替换高亮
  533. function highlightWithGlobalReplace(content, error) {
  534. var escapedWord = escapeRegExp(error.wrongWord);
  535. var regex = new RegExp(escapedWord, 'g');
  536. return content.replace(regex, function(match) {
  537. return '<span class="error-highlight" data-error-id="' + error.id + '">' + match + '</span>';
  538. });
  539. }
  540. // 转义正则表达式特殊字符
  541. function escapeRegExp(string) {
  542. return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  543. }
  544. // 获取纯文本
  545. function getPlainText(html) {
  546. var tempDiv = document.createElement('div');
  547. tempDiv.innerHTML = html;
  548. return tempDiv.textContent || tempDiv.innerText || "";
  549. }
  550. // 标记误报
  551. function markAsFalsePositive(id, wrongWord, correctWord, button) {
  552. falsePositiveErrors.push(id);
  553. $(button).addClass('reported').html('<i class="fa fa-check"></i> 已标记').prop('disabled', true);
  554. clearErrorHighlights();
  555. highlightErrors(currentErrors);
  556. var data = { "id": id, "res": 1 };
  557. $.get(wordResults + "/edit", data, function(result) {
  558. if (result.code == web_status.SUCCESS) {
  559. let errorData = result.data;
  560. }
  561. });
  562. }
  563. // 使用事件委托处理误报按钮点击
  564. $(document).on('click', '.false-positive-btn', function(e) {
  565. e.preventDefault();
  566. if ($(this).prop('disabled')) {
  567. return;
  568. }
  569. var wrongWord = $(this).data('wrong');
  570. var correctWord = $(this).data('correct');
  571. var id = $(this).data('id');
  572. markAsFalsePositive(id, wrongWord, correctWord, this);
  573. });
  574. // 校对功能
  575. $('#checkBtn').click(function() {
  576. clearErrorHighlights();
  577. var content = $('.summernote').summernote('code');
  578. if (content == '' || content == null || content == '<p><br></p>' || $.trim(content.replace(/<[^>]*>/g, '')) === '') {
  579. alert('请输入校对内容');
  580. return false;
  581. }
  582. showLoading();
  583. var requestData = {
  584. content: content,
  585. title: "文本校对",
  586. type: "1"
  587. };
  588. $.ajax({
  589. url: prefix + "/jiaodui",
  590. type: 'POST',
  591. contentType: 'application/json',
  592. data: JSON.stringify(requestData),
  593. success: function(result) {
  594. if (result.code == 0) {
  595. let errorData = result.data;
  596. currentErrors = errorData;
  597. console.log('收到错误数据:', errorData);
  598. if (errorData && errorData.length > 0) {
  599. highlightErrors(errorData);
  600. }
  601. let resultHtml = '';
  602. const errorsByType = {};
  603. if (errorData && errorData.length > 0) {
  604. errorData.forEach(error => {
  605. if (!errorsByType[error.errorType]) {
  606. errorsByType[error.errorType] = [];
  607. }
  608. errorsByType[error.errorType].push(error);
  609. });
  610. Object.keys(errorsByType).forEach(errorType => {
  611. const errors = errorsByType[errorType];
  612. let errorTypeHtml = '';
  613. errors.forEach((error, index) => {
  614. const isFalsePositive = falsePositiveErrors.includes(error.id);
  615. errorTypeHtml += `
  616. <div class="error-content">
  617. <h4>${index + 1}、${error.wrongWord}</h4>
  618. <table class="suggestion-table">
  619. <tr>
  620. <th>修改建议</th>
  621. <td>${error.correctWord}</td>
  622. </tr>
  623. ${error.source ? `<tr><th>参考依据</th><td>${error.source}</td></tr>` : ''}
  624. </table>
  625. <div class="error-actions">
  626. <button class="false-positive-btn" data-id="${error.id}" data-wrong="${error.wrongWord}" data-correct="${error.correctWord}" ${isFalsePositive ? 'disabled' : ''}>
  627. <i class="fa ${isFalsePositive ? 'fa-check' : 'fa-flag'}"></i> ${isFalsePositive ? '已标记' : '误报'}
  628. </button>
  629. </div>
  630. </div>
  631. `;
  632. });
  633. resultHtml += `
  634. <div class="error-item">
  635. <div class="error-title">${errorType}(${errors.length})</div>
  636. ${errorTypeHtml}
  637. </div>
  638. <div class="error-type-divider"></div>
  639. `;
  640. });
  641. resultHtml = resultHtml.replace(/<div class="error-type-divider"><\/div>$/, '');
  642. } else {
  643. resultHtml = `
  644. <div class="text-muted" style="text-align: center; padding: 20px;">
  645. <i class="fa fa-check-circle fa-2x" style="color:#1ab394"></i>
  646. <p>未发现需要修改的内容</p>
  647. </div>
  648. `;
  649. }
  650. $('#checkResults').html(resultHtml);
  651. // 手机版自动滚动到结果区域
  652. if ($(window).width() <= 768) {
  653. $('html, body').animate({
  654. scrollTop: $('#resultsPanel').offset().top
  655. }, 500);
  656. }
  657. } else {
  658. $.modal.alertError(result.msg);
  659. }
  660. },
  661. error: function(xhr, status, error) {
  662. var errorMsg = '请求失败: ';
  663. if (xhr.status === 413) {
  664. errorMsg = '文本内容过大,请减少内容后重试';
  665. } else if (xhr.status === 0) {
  666. errorMsg = '网络连接失败,请检查网络后重试';
  667. } else {
  668. errorMsg += error;
  669. }
  670. $.modal.alertError(errorMsg);
  671. },
  672. complete: function() {
  673. hideLoading();
  674. }
  675. });
  676. });
  677. $('#resetBtn').click(function() {
  678. clearErrorHighlights();
  679. $('.summernote').summernote('code', initialContent);
  680. $('#checkResults').html('<div class="text-muted" style="text-align: center; padding: 20px;"><i class="fa fa-info-circle fa-2x"></i><p>内容已重置,请重新校对</p></div>');
  681. toastr.success('内容已重置为初始状态');
  682. currentErrors = [];
  683. falsePositiveErrors = [];
  684. });
  685. $('#clearBtn').click(function() {
  686. if(confirm('确定要清空编辑器内容吗?')) {
  687. clearErrorHighlights();
  688. $('.summernote').summernote('reset');
  689. $('#checkResults').html('<div class="text-muted" style="text-align: center; padding: 20px;"><i class="fa fa-info-circle fa-2x"></i><p>内容已清空,请重新校对</p></div>');
  690. toastr.info('编辑器内容已清空');
  691. currentErrors = [];
  692. falsePositiveErrors = [];
  693. }
  694. });
  695. });
  696. </script>
  697. </body>
  698. </html>