diff --git a/package-lock.json b/package-lock.json
index 01693cc..82cdf13 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,7 @@
"@google/genai": "^1.29.0",
"@tailwindcss/vite": "^4.1.14",
"@vitejs/plugin-react": "^5.0.4",
+ "diff": "^9.0.0",
"dotenv": "^17.2.3",
"express": "^4.21.2",
"lucide-react": "^0.546.0",
@@ -1957,6 +1958,15 @@
"node": ">=8"
}
},
+ "node_modules/diff": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz",
+ "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
"node_modules/dotenv": {
"version": "17.4.2",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
diff --git a/package.json b/package.json
index 9e3207d..57eaf04 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"@google/genai": "^1.29.0",
"@tailwindcss/vite": "^4.1.14",
"@vitejs/plugin-react": "^5.0.4",
+ "diff": "^9.0.0",
"dotenv": "^17.2.3",
"express": "^4.21.2",
"lucide-react": "^0.546.0",
diff --git a/src/pages/ReportEditor.tsx b/src/pages/ReportEditor.tsx
index 8a0cf7d..3809ac7 100644
--- a/src/pages/ReportEditor.tsx
+++ b/src/pages/ReportEditor.tsx
@@ -12,6 +12,7 @@ import { User, Report, Template, CapturedFrame, SystemSettings, FormField, DEFAU
import { defaultReportContent } from '../utils/defaultContent';
import { printDocument } from '../utils/print';
import { storage } from '../utils/storage';
+import { diffChars } from 'diff';
export default function ReportEditor() {
const navigate = useNavigate();
@@ -823,6 +824,28 @@ export default function ReportEditor() {
}).filter(r => r.id);
};
+ const stripHtml = (html: string): string => {
+ const tmp = document.createElement('div');
+ tmp.innerHTML = html.replace(/<\/p>/gi, '
\n').replace(/
/gi, '\n');
+ return (tmp.innerText || tmp.textContent || '').trim();
+ };
+
+ const computeDiffHtml = (oldText: string, newText: string, side: 'left' | 'right'): string => {
+ const diffs = diffChars(oldText, newText);
+ let html = '';
+ for (const part of diffs) {
+ let value = part.value.replace(//g, '>').replace(/\n/g, '
');
+ if (side === 'left' && part.removed) {
+ html += `${value}`;
+ } else if (side === 'right' && part.added) {
+ html += `${value}`;
+ } else if (!part.added && !part.removed) {
+ html += value;
+ }
+ }
+ return html;
+ };
+
const toggleListening = () => {
if (isListening) {
setIsListening(false);
@@ -952,6 +975,9 @@ export default function ReportEditor() {
if (responseJson.reply) {
setChatMessages(prev => [...prev, { id: Date.now().toString(), role: 'model', content: responseJson.reply }]);
}
+ if (aiModifyEnabled && !responseJson.updatedHtml) {
+ setChatMessages(prev => [...prev, { id: Date.now().toString(), role: 'model', content: '【系统提示】AI 未能生成修改内容,请尝试重新描述您的需求。' }]);
+ }
if (responseJson.updatedHtml && aiModifyEnabled) {
let cleanHtml = responseJson.updatedHtml;
cleanHtml = cleanHtml.replace(/
/gi, '');
@@ -981,6 +1007,7 @@ export default function ReportEditor() {
const confirmAiInjection = (newHtml: string, regionId: string) => {
if (!editorRef.current) return;
+ const cleanHtml = newHtml.replace(/]*>(.*?)<\/span>/gi, '$2');
const targetContent = editorRef.current.querySelector(`.ai-region[data-ai-id="${regionId}"] .ai-content`) as HTMLElement;
if (targetContent) {
targetContent.focus();
@@ -2623,27 +2650,35 @@ export default function ReportEditor() {
-
-
-
-
-
AI 提议版本 (可直接编辑)
-
编辑态
+ {(() => {
+ const oldText = stripHtml(diffModal.originalHtml);
+ const newText = stripHtml(diffModal.newHtml);
+ const leftDiffHtml = computeDiffHtml(oldText, newText, 'left');
+ const rightDiffHtml = computeDiffHtml(oldText, newText, 'right');
+ return (
+
+
+
+
+ AI 提议版本 (可直接编辑)
+ 编辑态
+
+
setDiffModal(prev => prev ? { ...prev, newHtml: e.target.innerHTML } : null)}
+ dangerouslySetInnerHTML={{ __html: rightDiffHtml }}
+ style={{ fontFamily: 'SimSun, "Microsoft YaHei", serif', fontSize: '12pt', lineHeight: '1.5' }}
+ >
+
-
setDiffModal(prev => prev ? { ...prev, newHtml: e.target.innerHTML } : null)}
- dangerouslySetInnerHTML={{ __html: diffModal.newHtml }}
- style={{ fontFamily: 'SimSun, "Microsoft YaHei", serif', fontSize: '12pt', lineHeight: '1.5' }}
- >
-
-
+ );
+ })()}