<!DOCTYPE html>
<html lang="zh">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Summernote富文本编辑器</title>
	<th:block th:include="include :: header('Summernote富文本编辑器')" />
	<th:block th:include="include :: summernote-css" />
	<style>
		.result-panel {
			border-left: 1px solid #e7eaec;
			height: 100%;
			padding: 15px;
			background-color: #f9f9f9;
		}
		.error-item {
			margin-bottom: 20px;
			padding: 15px;
			border-radius: 5px;
			background-color: #fff;
			box-shadow: 0 2px 5px rgba(0,0,0,0.1);
		}
		.error-title {
			font-weight: bold;
			margin-bottom: 12px;
			font-size: 16px;
			color: #ed5565;
		}

		.common-error .error-title {
			color: #ed5565;
		}
		.political-error .error-title {
			color: #ed5565;
		}
		.suggestion-table {
			width: 100%;
			margin-bottom: 10px;
			border-collapse: collapse;
			word-break: break-all;
			word-wrap: break-word;
			white-space: normal;
		}
		.suggestion-table th, .suggestion-table td {
			padding: 8px;
			border: 1px solid #ddd;
			text-align: left;
		}
		.suggestion-table th {
			width: 80px;
			background-color: #f9f9f9;
		}
		.confidence {
			font-size: 12px;
			color: #888;
			margin-top: 5px;
		}
		.political-warning {
			font-weight: bold;
		}
		.error-highlight {
			background-color: #ffcccc !important;
			color: #ed5565 !important;
			border-bottom: 1px dashed #ed5565 !important;
			padding: 0 2px !important;
		}
		.error-content a {
			display: inline-block;
			max-width: 200px;
			overflow: hidden;
			text-overflow: ellipsis;
			white-space: nowrap;
			vertical-align: bottom;
		}

		/* 编辑器容器固定高度 */
		.ibox-content.no-padding {
			height: 650px;
			display: flex;
			flex-direction: column;
			position: relative;
		}

		/* 编辑器区域自动滚动 */
		.summernote {
			flex: 1;
			display: flex;
			flex-direction: column;
		}

		/* Summernote编辑器包装器 */
		.note-editor {
			flex: 1;
			display: flex;
			flex-direction: column;
			overflow: hidden;
		}

		/* Summernote编辑区域 */
		.note-editable {
			flex: 1;
			overflow-y: auto !important;
			min-height: 200px;
		}

		/* 底部按钮固定在容器底部 */
		.editor-footer {
			position: sticky;
			bottom: 0;
			background-color: #fff;
			z-index: 100;
			padding: 15px;
			border-top: 1px solid #e7eaec;
			text-align: center;
		}

		/* 校对结果面板样式 - 电脑版 */
		.col-sm-4 {
			position: fixed !important;
			right: 0px !important;
			z-index: 1000 !important;
			max-height: 80vh !important;
		}

		.col-sm-4 .ibox-content {
			max-height: calc(96vh - 50px) !important;
			overflow-y: auto !important;
		}

		/* 新增误报按钮样式 */
		.false-positive-btn {
			font-size: 12px;
			background-color: #f8f9fa;
			border: 1px solid #ddd;
			border-radius: 3px;
			color: #6c757d;
			cursor: pointer;
			transition: all 0.2s;
			display: block;
			text-align: center;
			padding: 4px 8px;
			margin-top: 8px;
		}
		.false-positive-btn:hover {
			background-color: #e9ecef;
			color: #495057;
		}
		.false-positive-btn.reported {
			color: #155724;
			border-color: #c3e6cb;
			cursor: default;
		}
		.false-positive-btn i {
			margin-right: 4px;
		}
		.error-actions {
			margin-bottom: 10px;
			text-align: right;
		}

		.error-type-divider {
			margin: 15px 0;
			border-top: 1px dashed #e7eaec;
		}

		/* 加载状态样式 */
		.loading-overlay {
			position: absolute;
			top: 0;
			left: 0;
			right: 0;
			bottom: 0;
			background: rgba(255, 255, 255, 0.8);
			display: flex;
			align-items: center;
			justify-content: center;
			z-index: 1000;
		}

		/* ========== 手机版适配样式 ========== */
		@media (max-width: 768px) {
			/* 整体布局调整 */
			.wrapper-content {
				padding: 10px;
			}

			.row {
				display: block;
				margin: 0;
			}

			/* 编辑器区域 - 全宽度 */
			.col-sm-8 {
				width: 100%;
				padding: 0;
				margin-bottom: 0;
			}

			/* 结果面板 - 手机版改为正常文档流，在编辑器下方 */
			.col-sm-4 {
				position: static !important;
				width: 100% !important;
				max-height: none !important;
				margin-top: 20px;
			}

			.col-sm-4 .ibox-content {
				max-height: none !important;
				height: auto;
				min-height: 300px;
				max-height: 500px;
				overflow-y: auto;
			}

			/* 编辑器高度调整 */
			.ibox-content.no-padding {
				height: 500px;
			}

			/* 按钮调整 */
			.editor-footer .btn {
				padding: 10px 15px;
				font-size: 14px;
				margin: 0 5px;
			}

			/* 表格字体调整 */
			.suggestion-table {
				font-size: 14px;
			}

			.suggestion-table th,
			.suggestion-table td {
				padding: 10px 8px;
			}

			/* 错误项间距调整 */
			.error-item {
				padding: 12px;
				margin-bottom: 15px;
			}

			.error-title {
				font-size: 16px;
			}

			/* Summernote 工具栏优化 */
			.note-toolbar {
				padding: 8px !important;
			}

			.note-toolbar .btn-group {
				margin-bottom: 5px;
			}

			.note-toolbar .btn {
				padding: 8px 10px;
				font-size: 13px;
			}

			.note-editable {
				font-size: 16px; /* 手机端字体放大 */
			}

			/* 手机版底部间距 */
			.wrapper {
				padding-bottom: 20px;
			}
		}

		/* 超小屏幕设备 */
		@media (max-width: 480px) {
			.ibox-content.no-padding {
				height: 400px;
			}

			.editor-footer .btn {
				padding: 8px 12px;
				font-size: 13px;
				margin: 0 3px;
			}

			.suggestion-table {
				font-size: 13px;
			}

			.error-content h4 {
				font-size: 15px;
			}

			.col-sm-4 .ibox-content {
				min-height: 250px;
				max-height: 400px;
			}
		}
	</style>
</head>
<body class="gray-bg">
<div class="wrapper wrapper-content">
	<div class="row">
		<!-- 编辑器区域 -->
		<div class="col-sm-8">
			<div class="ibox float-e-margins">
				<div class="ibox-content no-padding" style="position: relative;">
					<!-- 加载遮罩层 -->
					<div id="loadingOverlay" class="loading-overlay" style="display: none;">
						<div style="text-align: center;">
							<i class="fa fa-spinner fa-spin fa-3x fa-fw" style="color: #1ab394;"></i>
							<p style="margin-top: 15px; font-size: 16px;">校对中，请稍候...</p>
						</div>
					</div>
					<div class="summernote"></div>
					<div class="editor-footer">
						<button id="checkBtn" class="btn btn-primary btn-sm">
							<i class="fa fa-check"></i> 校对
						</button>
						<button id="resetBtn" class="btn btn-warning btn-sm">
							<i class="fa fa-refresh"></i> 重置
						</button>
						<button id="clearBtn" class="btn btn-danger btn-sm">
							<i class="fa fa-trash"></i> 清空
						</button>
					</div>
				</div>
			</div>
		</div>

		<!-- 结果面板区域 -->
		<div class="col-sm-4" id="resultsPanel">
			<!-- 新增：独立的安全警告模块 -->
			<div class="security-alert-panel" style="
        background: linear-gradient(135deg, #fff5f5, #ffe6e6);
        border: 2px solid #ff4d4f;
        border-radius: 8px;
        margin-bottom: 15px;
        padding: 15px;
        box-shadow: 0 3px 10px rgba(255, 77, 79, 0.2);
    ">
				<div style="
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10px;
        ">
					<i class="fa fa-exclamation-triangle" style="
                color: #ff4d4f;
                font-size: 20px;
                flex-shrink: 0;
            "></i>
					<div style="
                color: #ff4d4f;
                font-weight: bold;
                font-size: 15px;
                text-align: center;
                line-height: 1.4;
            ">
						严禁处理涉密信息<br>
						<span style="
                    font-size: 12px;
                    font-weight: normal;
                    color: #d9363e;
                    margin-top: 3px;
                    display: block;
                ">
                </span>
					</div>
				</div>
			</div>


			<div class="ibox float-e-margins fixed-result-panel">
				<div class="ibox-title">
					<h5>校对结果</h5>
				</div>
				<div class="ibox-content result-panel">
					<div id="checkResults">
						<div class="text-muted" style="text-align: center; padding: 20px;">
							<i class="fa fa-info-circle fa-2x"></i>
							<p>点击"校对"按钮检查文档内容</p>
						</div>
					</div>
				</div>
			</div>
		</div>
	</div>
</div>

<th:block th:include="include :: footer" />
<th:block th:include="include :: summernote-js" />
<script>
	var initialContent = '';
	var prefix = ctx + "project/jiaodui";
	var wordResults = ctx + "project/wordresults";
	var currentErrors = [];
	var falsePositiveErrors = [];

	$(document).ready(function () {
		// Summernote 初始化
		$('.summernote').summernote({
			lang: 'zh-CN',
			height: 460,
			toolbar: [
				['style', ['bold', 'italic', 'underline', 'clear']],
				['font', ['strikethrough', 'superscript', 'subscript']],
				['fontsize', ['fontsize']],
				['color', ['color']],
				['para', ['ul', 'ol', 'paragraph']],
				['height', ['height']],
				['insert', ['picture', 'link', 'video', 'table', 'hr']],
				['view', ['fullscreen', 'codeview', 'help']]
			]
		});

		// 显示加载状态
		function showLoading() {
			$('#loadingOverlay').show();
			$('#checkBtn').prop('disabled', true);
		}

		// 隐藏加载状态
		function hideLoading() {
			$('#loadingOverlay').hide();
			$('#checkBtn').prop('disabled', false);
		}

		// 清除所有错误高亮
		function clearErrorHighlights() {
			var content = $('.summernote').summernote('code');
			content = content.replace(/<span class="error-highlight"[^>]*>(.*?)<\/span>/gi, '$1');
			$('.summernote').summernote('code', content);
		}

		// 高亮显示错误词 - 完整版
		function highlightErrors(errors) {
			var content = $('.summernote').summernote('code');

			// 先清除旧的高亮
			content = clearErrorHighlightsFromContent(content);

			// 分离有位置信息和无位置信息的错误
			var errorsWithPosition = [];
			var errorsWithoutPosition = [];

			errors.forEach(function(error) {
				if (falsePositiveErrors.includes(error.id)) {
					return;
				}

				// 检查是否有有效的起止位置信息
				if (isValidPosition(error)) {
					errorsWithPosition.push(error);
				} else {
					errorsWithoutPosition.push(error);
				}
			});

			console.log('有位置信息的错误:', errorsWithPosition.length);
			console.log('无位置信息的错误:', errorsWithoutPosition.length);

			// 先处理有位置信息的错误（从后往前）
			if (errorsWithPosition.length > 0) {
				content = highlightErrorsWithPosition(content, errorsWithPosition);
			}

			// 再处理无位置信息的错误
			if (errorsWithoutPosition.length > 0) {
				content = highlightErrorsWithoutPosition(content, errorsWithoutPosition);
			}

			$('.summernote').summernote('code', content);
		}

		// 检查位置信息是否有效
		function isValidPosition(error) {
			return error.startpos !== undefined &&
					error.endpos !== undefined &&
					error.startpos >= 0 &&
					error.endpos > error.startpos &&
					error.wrongWord;
		}

		// 从内容中清除高亮（不更新编辑器）
		function clearErrorHighlightsFromContent(content) {
			return content.replace(/<span class="error-highlight"[^>]*>(.*?)<\/span>/gi, '$1');
		}

		// 高亮有位置信息的错误
		function highlightErrorsWithPosition(htmlContent, errors) {
			var plainText = getPlainText(htmlContent);

			console.log('纯文本长度:', plainText.length);
			console.log('纯文本内容:', plainText);

			// 按位置从后往前高亮，避免位置偏移
			errors.sort((a, b) => b.startpos - a.startpos).forEach(function(error, index) {
				console.log(`处理错误 ${index + 1}:`, error);

				try {
					var newContent = highlightSingleErrorWithPosition(htmlContent, plainText, error);
					if (newContent) {
						htmlContent = newContent;
					} else {
						// 位置高亮失败，回退到全局替换
						console.warn('位置高亮失败，使用全局替换:', error.wrongWord);
						htmlContent = highlightWithGlobalReplace(htmlContent, error);
					}
				} catch (e) {
					console.error('位置高亮异常，使用全局替换:', error.wrongWord, e);
					htmlContent = highlightWithGlobalReplace(htmlContent, error);
				}
			});

			return htmlContent;
		}

		// 高亮单个有位置信息的错误
		function highlightSingleErrorWithPosition(htmlContent, plainText, error) {
			var errorText = plainText.substring(error.startpos, error.endpos);

			console.log('期望的错误文本:', error.wrongWord);
			console.log('实际提取的文本:', errorText);
			console.log('位置范围:', error.startpos, '-', error.endpos);

			// 验证提取的文本是否匹配
			if (errorText !== error.wrongWord) {
				console.warn('位置信息不准确，期望:', error.wrongWord, '实际:', errorText);
				return null;
			}

			// 使用DOM方式精确定位
			var tempDiv = document.createElement('div');
			tempDiv.innerHTML = htmlContent;

			var result = findAndHighlightTextNode(tempDiv, error, plainText);
			if (result.found) {
				return tempDiv.innerHTML;
			} else {
				return null;
			}
		}

		// 查找并高亮文本节点
		function findAndHighlightTextNode(element, error, plainText) {
			var walker = document.createTreeWalker(
					element,
					NodeFilter.SHOW_TEXT,
					null,
					false
			);

			var currentGlobalPos = 0;
			var node = walker.nextNode();

			while (node) {
				var nodeText = node.textContent;
				var nodeLength = nodeText.length;

				// 检查错误是否在这个文本节点中
				if (error.startpos >= currentGlobalPos && error.endpos <= currentGlobalPos + nodeLength) {
					var nodeStart = error.startpos - currentGlobalPos;
					var nodeEnd = error.endpos - currentGlobalPos;

					// 验证节点内的文本是否匹配
					var nodeErrorText = nodeText.substring(nodeStart, nodeEnd);
					if (nodeErrorText === error.wrongWord) {
						// 创建高亮span
						var span = document.createElement('span');
						span.className = 'error-highlight';
						span.setAttribute('data-error-id', error.id);
						span.textContent = nodeErrorText;

						// 替换文本节点
						var beforeText = nodeText.substring(0, nodeStart);
						var afterText = nodeText.substring(nodeEnd);

						var parent = node.parentNode;
						if (beforeText) {
							parent.insertBefore(document.createTextNode(beforeText), node);
						}
						parent.insertBefore(span, node);
						if (afterText) {
							parent.insertBefore(document.createTextNode(afterText), node);
						}
						parent.removeChild(node);

						return { found: true };
					}
				}

				currentGlobalPos += nodeLength;
				node = walker.nextNode();
			}

			return { found: false };
		}

		// 高亮无位置信息的错误（全局替换）
		function highlightErrorsWithoutPosition(content, errors) {
			errors.forEach(function(error) {
				content = highlightWithGlobalReplace(content, error);
			});
			return content;
		}

		// 全局文本替换高亮
		function highlightWithGlobalReplace(content, error) {
			var escapedWord = escapeRegExp(error.wrongWord);
			var regex = new RegExp(escapedWord, 'g');

			return content.replace(regex, function(match) {
				return '<span class="error-highlight" data-error-id="' + error.id + '">' + match + '</span>';
			});
		}

		// 转义正则表达式特殊字符
		function escapeRegExp(string) {
			return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
		}

		// 获取纯文本
		function getPlainText(html) {
			var tempDiv = document.createElement('div');
			tempDiv.innerHTML = html;
			return tempDiv.textContent || tempDiv.innerText || "";
		}

		// 标记误报
		function markAsFalsePositive(id, wrongWord, correctWord, button) {
			falsePositiveErrors.push(id);
			$(button).addClass('reported').html('<i class="fa fa-check"></i> 已标记').prop('disabled', true);
			clearErrorHighlights();
			highlightErrors(currentErrors);

			var data = { "id": id, "res": 1 };
			$.get(wordResults + "/edit", data, function(result) {
				if (result.code == web_status.SUCCESS) {
					let errorData = result.data;
				}
			});
		}

		// 使用事件委托处理误报按钮点击
		$(document).on('click', '.false-positive-btn', function(e) {
			e.preventDefault();
			if ($(this).prop('disabled')) {
				return;
			}
			var wrongWord = $(this).data('wrong');
			var correctWord = $(this).data('correct');
			var id = $(this).data('id');
			markAsFalsePositive(id, wrongWord, correctWord, this);
		});

		// 校对功能
		$('#checkBtn').click(function() {
			clearErrorHighlights();
			var content = $('.summernote').summernote('code');

			// 清除src和href属性中的内容（保留属性名）
			if (content && content !== '') {
				// 清除src属性中的内容（替换为#或空值）
				content = content.replace(/src="[^"]*"/gi, 'src=""');

				// 清除href属性中的内容（替换为#或空值）
				content = content.replace(/href="[^"]*"/gi, 'href="#"');
			}

			if (content == '' || content == null || content == '<p><br></p>' || $.trim(content.replace(/<[^>]*>/g, '')) === '') {
				alert('请输入校对内容');
				return false;
			}

			showLoading();

			var requestData = {
				content: content,
				title: "文本校对",
				type: "1"
			};

			$.ajax({
				url: prefix + "/jiaodui",
				type: 'POST',
				contentType: 'application/json',
				data: JSON.stringify(requestData),
				success: function(result) {
					if (result.code == 0) {
						let errorData = result.data;
						currentErrors = errorData;

						console.log('收到错误数据:', errorData);

						if (errorData && errorData.length > 0) {
							highlightErrors(errorData);
						}

						let resultHtml = '';
						const errorsByType = {};

						if (errorData && errorData.length > 0) {
							errorData.forEach(error => {
								if (!errorsByType[error.errorType]) {
									errorsByType[error.errorType] = [];
								}
								errorsByType[error.errorType].push(error);
							});

							Object.keys(errorsByType).forEach(errorType => {
								const errors = errorsByType[errorType];
								let errorTypeHtml = '';

								errors.forEach((error, index) => {
									const isFalsePositive = falsePositiveErrors.includes(error.id);

									errorTypeHtml += `
                                    <div class="error-content">
                                        <h4>${index + 1}、${error.wrongWord}</h4>
                                        <table class="suggestion-table">
                                            <tr>
                                                <th>修改建议</th>
                                                <td>${error.correctWord}</td>
                                            </tr>
                                            ${error.source ? `<tr><th>参考依据</th><td>${error.source}</td></tr>` : ''}
                                        </table>
                                        <div class="error-actions">
                                            <button class="false-positive-btn" data-id="${error.id}" data-wrong="${error.wrongWord}" data-correct="${error.correctWord}" ${isFalsePositive ? 'disabled' : ''}>
                                                <i class="fa ${isFalsePositive ? 'fa-check' : 'fa-flag'}"></i> ${isFalsePositive ? '已标记' : '误报'}
                                            </button>
                                        </div>
                                    </div>
                                `;
								});

								resultHtml += `
                                <div class="error-item">
                                    <div class="error-title">${errorType}（${errors.length}）</div>
                                    ${errorTypeHtml}
                                </div>
                                <div class="error-type-divider"></div>
                            `;
							});

							resultHtml = resultHtml.replace(/<div class="error-type-divider"><\/div>$/, '');
						} else {
							resultHtml = `
                            <div class="text-muted" style="text-align: center; padding: 20px;">
                                <i class="fa fa-check-circle fa-2x" style="color:#1ab394"></i>
                                <p>未发现需要修改的内容</p>
                            </div>
                        `;
						}

						$('#checkResults').html(resultHtml);

						// 手机版自动滚动到结果区域
						if ($(window).width() <= 768) {
							$('html, body').animate({
								scrollTop: $('#resultsPanel').offset().top
							}, 500);
						}
					} else {
						$.modal.alertError(result.msg);
					}
				},
				error: function(xhr, status, error) {
					var errorMsg = '请求失败: ';
					if (xhr.status === 413) {
						errorMsg = '文本内容过大，请减少内容后重试';
					} else if (xhr.status === 0) {
						errorMsg = '网络连接失败，请检查网络后重试';
					} else {
						errorMsg += error;
					}
					$.modal.alertError(errorMsg);
				},
				complete: function() {
					hideLoading();
				}
			});
		});

		$('#resetBtn').click(function() {
			clearErrorHighlights();
			$('.summernote').summernote('code', initialContent);
			$('#checkResults').html('<div class="text-muted" style="text-align: center; padding: 20px;"><i class="fa fa-info-circle fa-2x"></i><p>内容已重置，请重新校对</p></div>');
			toastr.success('内容已重置为初始状态');
			currentErrors = [];
			falsePositiveErrors = [];
		});

		$('#clearBtn').click(function() {
			if(confirm('确定要清空编辑器内容吗？')) {
				clearErrorHighlights();
				$('.summernote').summernote('reset');
				$('#checkResults').html('<div class="text-muted" style="text-align: center; padding: 20px;"><i class="fa fa-info-circle fa-2x"></i><p>内容已清空，请重新校对</p></div>');
				toastr.info('编辑器内容已清空');
				currentErrors = [];
				falsePositiveErrors = [];
			}
		});
	});
</script>
</body>
</html>