diff --git a/apps/mobile/src/screens/WorkspaceScreen.tsx b/apps/mobile/src/screens/WorkspaceScreen.tsx index 714cb0bb..24935347 100644 --- a/apps/mobile/src/screens/WorkspaceScreen.tsx +++ b/apps/mobile/src/screens/WorkspaceScreen.tsx @@ -3115,7 +3115,8 @@ const RevisionHistoryModal = ({ const revisions = revisionsQuery.data?.revisions ?? []; const selectedRevision = revisions.find((revision) => revision.id === selectedRevisionId) ?? revisions[0] ?? null; - const changedLines = selectedRevision ? countChangedLines(selectedRevision.contentMarkdown, memo?.contentMarkdown ?? "") : 0; + const diffRows = selectedRevision ? buildRevisionDiffRows(selectedRevision.contentMarkdown, memo?.contentMarkdown ?? "") : null; + const changedLines = diffRows?.changed ?? 0; useEffect(() => { if (memo && revisions.length > 0 && !selectedRevisionId) { @@ -3213,11 +3214,11 @@ const RevisionHistoryModal = ({ 历史版本 - {selectedRevision.contentMarkdown || selectedRevision.contentText || "没有正文内容"} + 当前内容 - {memo?.contentMarkdown || memo?.contentText || "没有正文内容"} + ) : null} @@ -3231,6 +3232,36 @@ const RevisionHistoryModal = ({ ); }; +const RevisionDiffPreview = ({ rows, tone }: { rows: DiffRow[]; tone: "history" | "current" }) => { + const hasContent = rows.some((row) => row.text); + + if (!hasContent) { + return 没有正文内容; + } + + return ( + + {rows.map((row) => { + const changed = row.state === "changed"; + + return ( + + {row.lineNumber} + {row.text || " "} + + ); + })} + + ); +}; + const MemoDetailModal = ({ isDeleting, isLoading, @@ -4731,19 +4762,42 @@ const buildMcpRemoteConfig = (baseUrl: string, token: string) => 2 ); -const countChangedLines = (left: string, right: string) => { +type DiffRow = { + lineNumber: number; + text: string; + state: "same" | "changed" | "empty"; +}; + +const buildRevisionDiffRows = (left: string, right: string) => { const leftLines = left.split("\n"); const rightLines = right.split("\n"); - const maxLines = Math.max(leftLines.length, rightLines.length); + const maxLines = Math.max(leftLines.length, rightLines.length, 1); + const leftRows: DiffRow[] = []; + const rightRows: DiffRow[] = []; let changed = 0; for (let index = 0; index < maxLines; index += 1) { - if ((leftLines[index] ?? "") !== (rightLines[index] ?? "")) { + const leftText = leftLines[index] ?? ""; + const rightText = rightLines[index] ?? ""; + const isChanged = leftText !== rightText; + + if (isChanged) { changed += 1; } + + leftRows.push({ + lineNumber: index + 1, + text: leftText, + state: isChanged ? "changed" : leftText ? "same" : "empty", + }); + rightRows.push({ + lineNumber: index + 1, + text: rightText, + state: isChanged ? "changed" : rightText ? "same" : "empty", + }); } - return changed; + return { changed, leftRows, rightRows }; }; const formatRevisionActor = (actor: string) => { @@ -5833,6 +5887,45 @@ const styles = StyleSheet.create({ fontSize: 13, lineHeight: 20, }, + revisionDiffTable: { + borderColor: "#e2e8f0", + borderRadius: 8, + borderWidth: 1, + overflow: "hidden", + }, + revisionDiffRow: { + borderBottomColor: "#f1f5f9", + borderBottomWidth: 1, + flexDirection: "row", + minHeight: 28, + }, + revisionDiffRowHistory: { + backgroundColor: "#fffbeb", + }, + revisionDiffRowCurrent: { + backgroundColor: "#ecfdf5", + }, + revisionDiffLineNumber: { + borderRightColor: "#e2e8f0", + borderRightWidth: 1, + color: "#94a3b8", + fontSize: 11, + minWidth: 42, + paddingHorizontal: 8, + paddingTop: 6, + textAlign: "right", + }, + revisionDiffText: { + color: "#334155", + flex: 1, + fontSize: 12, + lineHeight: 18, + paddingHorizontal: 10, + paddingVertical: 5, + }, + revisionDiffTextEmpty: { + color: "#94a3b8", + }, label: { color: "#334155", fontSize: 13,